函数式编程和模拟对象

16

我最近观看了一个关于Clojure的网络研讨会,在其中演讲者在讨论Clojure的函数式编程本质时发表了一些评论,大致是这样说的(希望我没有曲解他的意思):“Mock对象正在嘲笑你”。

我之前也听过类似的评论,当时我观看了微软反应框架开始出现时的一次网络研讨会。那个评论大概是这样说的“Mock对象是为那些不懂数学的人准备的”。

现在我知道这两个评论都是玩笑/半开玩笑等等(可能被改述得很糟糕),但显然它们背后有一些我不理解的概念,因为我还没有真正转向函数式编程范式。

因此,我想请某人解释一下是否函数式编程确实使模拟变得多余了,如果是,那么是如何实现的。


6
在FP编程中,对象模拟你!/网络文化表情 - user395760
2个回答

14
在纯函数式编程中,你有具有引用透明性的函数,每次使用相同的输入调用它们时都会计算出相同的输出。因此,你需要将所有需要的状态作为参数进行显式传递,并将结果作为函数结果返回,没有任何以某种方式“隐藏在”调用的函数后面的有状态对象。然而,这正是你的模拟对象通常要做的事情:模拟一些外部的、隐藏的状态或行为,这些状态或行为是你的测试主体依赖的。
换句话说: 面向对象编程:你的对象结合了相关的状态和行为。 纯函数式编程:状态是你在函数之间传递的东西,而这些函数本身是无状态的,并且仅依赖于其他无状态的函数。

好的。但是假设在函数之间传递的状态可以在模拟对象或“真实对象”中,那么模拟对象仍然适用于测试FP解决方案,对吗? - Simon Woods
在纯函数式编程中,没有面向对象意义上的对象。只有数据结构,而这些数据结构可以由用户自定义。在某些语言中,有与接口类似的远亲:Haskell 有类型类,它们基本上是一组对于每个类型类中的数据类型都必须定义的函数。所以,是的,你可以编写一个操作特定类型类数据类型的函数,并在不同于你在生产中使用的数据类型上进行测试。在 F# 或 Scala 中,你可以实际以函数式风格操控 .NET 或 Java 对象,可能甚至需要使用真实的模拟对象。 - Christoph
你对这句话有何看法:间接调用功能的模拟会限制测试仅针对所调用的一个函数进行,因此做得更少且更有效率?我认为即使模拟本身并非纯净的,也可以在FP代码库上使用它,以获得相同效率和测试范围限制。 - Zelphir Kaltstahl

12

我认为需要考虑的重要事情是使用测试来帮助你构建代码的思想。模拟是关于推迟你现在不想做出决策的技术,但这是一个广为人误解的技术。除了对象状态之外,考虑使用部分函数。你可以编写一个函数,将其行为的一部分推迟到传入的部分函数中。在单元测试中,可以使用一个伪实现,让你专注于手头的代码。稍后,你可以使用真实实现将你的新代码组合起来构建系统。

实际上,在我们开发模拟的想法时,我总是这样认为模拟是这样的。对象部分只是附带的。


模拟是关于推迟你现在不想做出的决定。第一次看到有人如此精辟地表述它。 - Prasad Bhokare

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接