比方说,我有两个纯函数,pureFn1
和pureFn2
。这些功能必须通过类似的测试。
describe("generic function", () => {
it("should fulfill condition 1", testCondition1);
it("should fulfill condition 2", testCondition2);
it("should fulfill condition 3", testCondition3);
it("should fulfill condition 4", testCondition4);
});
如何针对这些功能编写类似的测试?测试套件应该可重用吗?
例如,如果我们重复使用测试套件,它将最终看起来像这样:
const reusableTestSuite = (codeUnderTest) => {
describe(`${codeUnderTest.name}`, () => {
it("should fulfill condition 1", testCondition1(codeUnderTest));
it("should fulfill condition 2", testCondition2(codeUnderTest));
it("should fulfill condition 3", testCondition3(codeUnderTest));
it("should fulfill condition 4", testCondition4(codeUnderTest));
});
};
reusableTestSuite(pureFn1);
reusableTestSuite(pureFn2);
这是非常干的,但是问题是存在一个抽象,可能会使测试难以阅读和修改,从而可能阻止开发人员以速度和便捷性为名编写更多测试。 this article的第8点对此进行了讨论。当这些抽象的测试中断时,下一个开发人员可能会讨厌阅读它。
另一种选择是复制粘贴测试:
describe("pureFn1", () => {
it("should fulfill condition 1", testCondition1Fn1);
it("should fulfill condition 2", testCondition2Fn1);
it("should fulfill condition 3", testCondition3Fn1);
it("should fulfill condition 4", testCondition4Fn1);
});
describe("pureFn2", () => {
it("should fulfill condition 1", testCondition1Fn2);
it("should fulfill condition 2", testCondition2Fn2);
it("should fulfill condition 3", testCondition3Fn2);
it("should fulfill condition 4", testCondition4Fn2);
});
这是完整的代码重复。没有抽象。如果我们有两个函数,并且它们之间有20个共同的属性,那么我们将不得不复制和粘贴20个测试,并且要记住,当一个变化时,要永远更新所有类似的测试。
那么在这些方法之间,哪种方法更好?还是有第三种方法,这是编写单元测试的最佳实践,它使我们获得了抽象的好处,同时又不使下一个开发人员很难立即了解出了什么问题,从而 not 阻止他们编写更多这些测试?