我的理解是 FP 对测试也有巨大的影响。没有可变状态通常会迫使您为函数提供比为类提供更多的数据。有一些权衡,但想想测试一个“incrementNumberByN”而不是“Counter”类的函数是多么容易。
目的
describe("counter", () => {
it("should increment the count by one when 'increment' invoked without
argument", () => {
const counter = new Counter(0)
counter.increment()
expect(counter.count).toBe(1)
})
it("should increment the count by n when 'increment' invoked with
argument", () => {
const counter = new Counter(0)
counter.increment(2)
expect(counter.count).toBe(2)
})
})
功能性的
describe("incrementNumberBy(startingNumber, increment)", () => {
it("should increment by 1 if n not supplied"){
expect(incrementNumberBy(0)).toBe(1)
}
it("should increment by 1 if n = 1 supplied"){
expect(countBy(0, 1)).toBe(1)
}
})
由于该函数没有状态并且输入的数据更明确,因此当您试图找出测试可能失败的原因时,需要关注的事情更少。在我们必须做的柜台测试中
const counter = new Counter(0)
counter.increment()
expect(counter.count).toBe(1)
前两行都对 的值有贡献counter.count
。在像这样的简单示例中,1 对 2 行可能有问题的代码没什么大不了的,但是当您处理更复杂的对象时,您的测试也可能会增加大量复杂性。
相反,当您使用函数式语言编写项目时,它会促使您保持花哨的算法依赖于流入和流出特定函数的数据,而不是依赖于系统的状态。
另一种看待它的方式是说明在每个范例中测试系统的心态。
对于函数式编程:确保函数 A 适用于给定输入,确保函数 B 适用于给定输入,确保 C 使用给定输入。
对于 OOP:在对对象的状态执行 Y 和 Z 之后,确保对象 A 的方法在给定输入参数 X 的情况下有效。在对对象的状态执行 W 和 Y 之后,确保对象 B 的方法在给定输入参数 X 的情况下有效。