我想知道如何用功能语言编写良好的单元测试。测试非常基本的功能并不难,但我不明白我应该如何测试使用其他功能的功能。
例如:
在面向对象的世界中,我自己测试了非常基本的功能,然后在测试更复杂的功能
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
功能已断开...
将"单位"视为行为单位。摘要仅使测试缓慢或使用全局应用状态的组件。
函数multiply
的add
是实现详细信息,将通过"高阶"功能进行测试。