我想知道如何用函数式语言编写好的单元测试。测试非常基本的功能并不难,但我不明白我应该如何测试使用其他功能的功能。
例如: 在面向对象的世界中,我自己测试非常基本的功能,并在测试更复杂的函数时模拟它
class Example {
internal var adder: Adder = AdderImpl()
internal var multiplier: Multiplier = MultiplierImpl()
fun execute(n: Int, m: Int): Int =
if (n < m) adder.add(n, m)
else multiplier.multiply(n, m)
}
如果测试Adder.add
和Multiplier.multiply
,我可以通过嘲笑这些来测试Example.execute
并期望adder
被称为n<m
和multiplier
被称为否则。
但是我怎么用函数式语言呢?我可以很容易地测试add
和multiply
函数,并从他们组成我的execute
execute : Int -> Int -> Int
execute =
if n < m then add n m
else multiply n m
现在测试execute
我不能简单地期望add
或multiply
被调用,因为我不能嘲笑他们。我实际上必须做我为add
编写的所有测试,如果n<m
执行它们,否则执行multiply
的所有测试。这意味着我测试了这两个功能两次。
那么测试较小函数和更大函数的正确函数方法是什么假设它们有效并且只检查它们是否在满足正确条件时被调用?
你的execute
函数有输入值和预期输出 - 你不应该关心它是如何实现的。
您将编写涵盖所有execute
函数的测试。
如果为了实现,你决定重用add
和multiply
方法以及execute
函数传递的所有测试 - 好工作 - 你已经创建了可重用的函数。
想象一下,您将决定改变add
方法的行为 - 您将更改add
函数的测试以满足新的要求 - 当您在更改后运行所有测试时 - 所有测试都通过,execute
函数的测试也将通过,因为您嘲笑它,但是实际上现在execute
功能被打破了...
将“单位”视为行为单位。摘要只有使测试变慢的组件或使用全局应用程序的组件。
add
的multiply
函数是实现细节,将通过“更高阶”函数进行测试。