Javascript 如何从单元测试中删除重复?
昨天,我用编写了一个单元测试,今天我发现我编写了一些重复的代码来执行相同的测试 我有一个文件:Javascript 如何从单元测试中删除重复?,javascript,jestjs,Javascript,Jestjs,昨天,我用编写了一个单元测试,今天我发现我编写了一些重复的代码来执行相同的测试 我有一个文件:null.spec.js包含以下测试: import ArrayNull from "../../../../../src/1.x.x/scripts/array/has/null"; describe("Array has any null value", () => { ....... it("should th
null.spec.js
包含以下测试:
import ArrayNull from "../../../../../src/1.x.x/scripts/array/has/null";
describe("Array has any null value", () => {
.......
it("should throw error if the parameter is not an array", () => {
function passNumber() {
ArrayNull.hasAnyNull(0);
}
function passString() {
ArrayNull.hasAnyNull("item");
}
expect(passNumber).toThrowError("The parameter should be an array");
expect(passString).toThrowError("The parameter should be an array");
});
it("should throw error if the parameter is undefined or null", () => {
function passUndefinedOrNull() {
ArrayNull.hasAnyNull(undefined || null);
}
expect(passUndefinedOrNull).toThrowError("The parameter is null or undefined");
});
it("should throw error if the array is empty", () => {
function pasEmptyArray() {
ArrayNull.hasAnyNull([]);
}
expect(pasEmptyArray).toThrowError("The array is empty");
});
});
describe("Array has at least a null value", () => {
...........
it("should throw error if the parameter is not an array", () => {
function passNumber() {
ArrayNull.hasAtLeastNull(0);
}
function passString() {
ArrayNull.hasAtLeastNull("item");
}
expect(passNumber).toThrowError("The parameter should be an array");
expect(passString).toThrowError("The parameter should be an array");
});
it("should throw error if the array is empty", () => {
function pasEmptyArray() {
ArrayNull.hasAtLeastNull([]);
}
expect(pasEmptyArray).toThrowError("The array is empty");
});
it("should throw error when the parameter is undefined or null", () => {
function passUndefinedOrNull() {
ArrayNull.hasAtLeastNull(undefined || null);
}
expect(passUndefinedOrNull).toThrowError("The parameter is null or undefined");
});
});
看看我是如何在每次测试中重复编写它的(“如果参数不是数组,则应抛出错误”,callback
),即使它做了相同的事情:抛出错误,但使用不同的函数
- 第一个功能是:
hasAnyNull()
- 第二个函数是:
hasAtLeastNull()
descripe(“数组有任何空值”,回调)
和
description(“数组至少有一个空值”,回调)`可以通过迭代值生成多个测试块:
[
['has any null', hasAnyNull],
['has at least a null', hasAtLeastNull]
].forEach(([description, fn]) => {
describe(`Array ${description} value`, () => {
it(...);
});
});
这可以就地完成,也可以提取到辅助函数
当涉及到重复的描述
块时,这正是所描述的。每个
都是这样做的,并添加了描述格式:
describe.each([
['has any null', hasAnyNull],
['has at least a null', hasAtLeastNull]
])('Array %s value', (_description, fn) => {
it(...);
});
重复数据消除本身并不是目的。如果干代码比湿代码可读性差且容易出错,这可能是应用程序代码中的一个问题,但在测试中肯定是一个问题。如果应用程序代码由于复杂性而未能达到预期,则预期会在测试中检测到这一点;这不适用于测试本身。可以通过迭代值生成多个测试块:
[
['has any null', hasAnyNull],
['has at least a null', hasAtLeastNull]
].forEach(([description, fn]) => {
describe(`Array ${description} value`, () => {
it(...);
});
});
这可以就地完成,也可以提取到辅助函数
当涉及到重复的描述
块时,这正是所描述的。每个
都是这样做的,并添加了描述格式:
describe.each([
['has any null', hasAnyNull],
['has at least a null', hasAtLeastNull]
])('Array %s value', (_description, fn) => {
it(...);
});
重复数据消除本身并不是目的。如果干代码比湿代码可读性差且容易出错,这可能是应用程序代码中的一个问题,但在测试中肯定是一个问题。如果应用程序代码由于复杂性而未能达到预期,则预期会在测试中检测到这一点;这不适用于测试本身。我通过以下方法解决了干燥问题:
使所有错误
抛出一个它(“应该抛出一个错误”)
而不提供详细信息
实现顶级功能\u throwError(func)
在其中传递回调函数func
以前的代码:
it("should throw error if the parameter is not an array", () => {
function passNumber() {
ArrayNull.hasAnyNull(0);
}
function passString() {
ArrayNull.hasAnyNull("item");
}
expect(passNumber).toThrowError("The parameter should be an array");
expect(passString).toThrowError("The parameter should be an array");
});
it("should throw error if the parameter is undefined or null", () => {
function passUndefinedOrNull() {
ArrayNull.hasAnyNull(undefined || null);
}
expect(passUndefinedOrNull).toThrowError("The parameter is null or undefined");
});
it("should throw error if the array is empty", () => {
function pasEmptyArray() {
ArrayNull.hasAnyNull([]);
}
expect(pasEmptyArray).toThrowError("The array is empty");
});
it("should throw an error", () => {
__throwError(ArrayNull.hasAnyNull);
});
function __throwError(func) {
function passNumber() {
func.length === 1 ? func(0) : func(0, 1)
}
function passString() {
func.length === 1 ? func("item") : func("item", 1);
}
function passEmptyArray() {
func.length === 1 ? func([]) : func([], 1);
}
function passUndefinedOrNull() {
func.length === 1 ? func(undefined || null) : func(undefined || null, 1);
}
expect(passNumber).toThrowError("The parameter should be an array");
expect(passString).toThrowError("The parameter should be an array");
expect(passEmptyArray).toThrowError("The array is empty");
expect(passUndefinedOrNull).toThrowError("The parameter is null or undefined");
}
当前代码:
it("should throw error if the parameter is not an array", () => {
function passNumber() {
ArrayNull.hasAnyNull(0);
}
function passString() {
ArrayNull.hasAnyNull("item");
}
expect(passNumber).toThrowError("The parameter should be an array");
expect(passString).toThrowError("The parameter should be an array");
});
it("should throw error if the parameter is undefined or null", () => {
function passUndefinedOrNull() {
ArrayNull.hasAnyNull(undefined || null);
}
expect(passUndefinedOrNull).toThrowError("The parameter is null or undefined");
});
it("should throw error if the array is empty", () => {
function pasEmptyArray() {
ArrayNull.hasAnyNull([]);
}
expect(pasEmptyArray).toThrowError("The array is empty");
});
it("should throw an error", () => {
__throwError(ArrayNull.hasAnyNull);
});
function __throwError(func) {
function passNumber() {
func.length === 1 ? func(0) : func(0, 1)
}
function passString() {
func.length === 1 ? func("item") : func("item", 1);
}
function passEmptyArray() {
func.length === 1 ? func([]) : func([], 1);
}
function passUndefinedOrNull() {
func.length === 1 ? func(undefined || null) : func(undefined || null, 1);
}
expect(passNumber).toThrowError("The parameter should be an array");
expect(passString).toThrowError("The parameter should be an array");
expect(passEmptyArray).toThrowError("The array is empty");
expect(passUndefinedOrNull).toThrowError("The parameter is null or undefined");
}
\u投掷者功能:
it("should throw error if the parameter is not an array", () => {
function passNumber() {
ArrayNull.hasAnyNull(0);
}
function passString() {
ArrayNull.hasAnyNull("item");
}
expect(passNumber).toThrowError("The parameter should be an array");
expect(passString).toThrowError("The parameter should be an array");
});
it("should throw error if the parameter is undefined or null", () => {
function passUndefinedOrNull() {
ArrayNull.hasAnyNull(undefined || null);
}
expect(passUndefinedOrNull).toThrowError("The parameter is null or undefined");
});
it("should throw error if the array is empty", () => {
function pasEmptyArray() {
ArrayNull.hasAnyNull([]);
}
expect(pasEmptyArray).toThrowError("The array is empty");
});
it("should throw an error", () => {
__throwError(ArrayNull.hasAnyNull);
});
function __throwError(func) {
function passNumber() {
func.length === 1 ? func(0) : func(0, 1)
}
function passString() {
func.length === 1 ? func("item") : func("item", 1);
}
function passEmptyArray() {
func.length === 1 ? func([]) : func([], 1);
}
function passUndefinedOrNull() {
func.length === 1 ? func(undefined || null) : func(undefined || null, 1);
}
expect(passNumber).toThrowError("The parameter should be an array");
expect(passString).toThrowError("The parameter should be an array");
expect(passEmptyArray).toThrowError("The array is empty");
expect(passUndefinedOrNull).toThrowError("The parameter is null or undefined");
}
我通过以下方式解决了干燥问题:
使所有错误
抛出一个它(“应该抛出一个错误”)
而不提供详细信息
实现顶级功能\u throwError(func)
在其中传递回调函数func
以前的代码:
it("should throw error if the parameter is not an array", () => {
function passNumber() {
ArrayNull.hasAnyNull(0);
}
function passString() {
ArrayNull.hasAnyNull("item");
}
expect(passNumber).toThrowError("The parameter should be an array");
expect(passString).toThrowError("The parameter should be an array");
});
it("should throw error if the parameter is undefined or null", () => {
function passUndefinedOrNull() {
ArrayNull.hasAnyNull(undefined || null);
}
expect(passUndefinedOrNull).toThrowError("The parameter is null or undefined");
});
it("should throw error if the array is empty", () => {
function pasEmptyArray() {
ArrayNull.hasAnyNull([]);
}
expect(pasEmptyArray).toThrowError("The array is empty");
});
it("should throw an error", () => {
__throwError(ArrayNull.hasAnyNull);
});
function __throwError(func) {
function passNumber() {
func.length === 1 ? func(0) : func(0, 1)
}
function passString() {
func.length === 1 ? func("item") : func("item", 1);
}
function passEmptyArray() {
func.length === 1 ? func([]) : func([], 1);
}
function passUndefinedOrNull() {
func.length === 1 ? func(undefined || null) : func(undefined || null, 1);
}
expect(passNumber).toThrowError("The parameter should be an array");
expect(passString).toThrowError("The parameter should be an array");
expect(passEmptyArray).toThrowError("The array is empty");
expect(passUndefinedOrNull).toThrowError("The parameter is null or undefined");
}
当前代码:
it("should throw error if the parameter is not an array", () => {
function passNumber() {
ArrayNull.hasAnyNull(0);
}
function passString() {
ArrayNull.hasAnyNull("item");
}
expect(passNumber).toThrowError("The parameter should be an array");
expect(passString).toThrowError("The parameter should be an array");
});
it("should throw error if the parameter is undefined or null", () => {
function passUndefinedOrNull() {
ArrayNull.hasAnyNull(undefined || null);
}
expect(passUndefinedOrNull).toThrowError("The parameter is null or undefined");
});
it("should throw error if the array is empty", () => {
function pasEmptyArray() {
ArrayNull.hasAnyNull([]);
}
expect(pasEmptyArray).toThrowError("The array is empty");
});
it("should throw an error", () => {
__throwError(ArrayNull.hasAnyNull);
});
function __throwError(func) {
function passNumber() {
func.length === 1 ? func(0) : func(0, 1)
}
function passString() {
func.length === 1 ? func("item") : func("item", 1);
}
function passEmptyArray() {
func.length === 1 ? func([]) : func([], 1);
}
function passUndefinedOrNull() {
func.length === 1 ? func(undefined || null) : func(undefined || null, 1);
}
expect(passNumber).toThrowError("The parameter should be an array");
expect(passString).toThrowError("The parameter should be an array");
expect(passEmptyArray).toThrowError("The array is empty");
expect(passUndefinedOrNull).toThrowError("The parameter is null or undefined");
}
\u投掷者功能:
it("should throw error if the parameter is not an array", () => {
function passNumber() {
ArrayNull.hasAnyNull(0);
}
function passString() {
ArrayNull.hasAnyNull("item");
}
expect(passNumber).toThrowError("The parameter should be an array");
expect(passString).toThrowError("The parameter should be an array");
});
it("should throw error if the parameter is undefined or null", () => {
function passUndefinedOrNull() {
ArrayNull.hasAnyNull(undefined || null);
}
expect(passUndefinedOrNull).toThrowError("The parameter is null or undefined");
});
it("should throw error if the array is empty", () => {
function pasEmptyArray() {
ArrayNull.hasAnyNull([]);
}
expect(pasEmptyArray).toThrowError("The array is empty");
});
it("should throw an error", () => {
__throwError(ArrayNull.hasAnyNull);
});
function __throwError(func) {
function passNumber() {
func.length === 1 ? func(0) : func(0, 1)
}
function passString() {
func.length === 1 ? func("item") : func("item", 1);
}
function passEmptyArray() {
func.length === 1 ? func([]) : func([], 1);
}
function passUndefinedOrNull() {
func.length === 1 ? func(undefined || null) : func(undefined || null, 1);
}
expect(passNumber).toThrowError("The parameter should be an array");
expect(passString).toThrowError("The parameter should be an array");
expect(passEmptyArray).toThrowError("The array is empty");
expect(passUndefinedOrNull).toThrowError("The parameter is null or undefined");
}
不要担心测试中的重复。DRY是一个帮助编写更好代码的工具,它本身并不是一个目标。是的,但它不是自动化的,我的意思是我手工编写,它需要不必要的时间,并且可能会导致无声的错误(来自打字错误)。编写更详细的测试,这样它们就不会因为打字错误而成为假阳性。使用TypeScript可以避免更多的打字错误。@EstusFlask,你能看一下我的答案吗?不要担心测试中的重复。DRY是一个帮助编写更好代码的工具,它本身并不是一个目标。是的,但它不是自动化的,我的意思是我手工编写,它需要不必要的时间,并且可能会导致无声的错误(来自打字错误)。编写更详细的测试,这样它们就不会因为打字错误而成为假阳性。使用TypeScript可以避免更多的打字错误。@EstusFlask,你能看一下我的答案吗?我想你的答案显示了代码中的另一个问题。我想你的答案显示了代码中的另一个问题。这正是我关于干与湿的意思__throwError在没有充分理由的情况下增加了复杂性,并落入了不必要的抽象范畴,这是一种反模式。更重要的是,只写代码在编写时是有意义的,但会影响维护,过一段时间后,需要花时间来弄清楚它到底做了什么,更重要的是,它是否正确。这不是你在测试中想要的东西,在测试中,亲吻会让你感觉干燥。重构10个这样的案例以获得一个好的公分母是有意义的,但其中2个不足以获得好的干法解决方案。Dan Abramov曾写过一篇关于初步重构的有意义的文章。@EstusFlask,但我将测试从85个减少到67个,并缩短了执行时间。如果测试质量受到影响,这不应该是优先事项。如果目标是减少测试计数,从而减少执行时间,那么您可以像使用_-throwError但不使用它一样,在较少的测试中执行更多断言。至于测试计数,这不一定是件好事。关于问题原因的测试报告越少,就越需要调查测试代码。这正是我关于干与湿的意思__throwError在没有充分理由的情况下增加了复杂性,并落入了不必要的抽象范畴,这是一种反模式。更重要的是,只写代码在编写时是有意义的,但会影响维护,过一段时间后,需要花时间来弄清楚它到底做了什么,更重要的是,它是否正确。这不是你在测试中想要的东西,在测试中,亲吻会让你感觉干燥。重构10个这样的案例以获得一个好的公分母是有意义的,但其中2个不足以获得好的干法解决方案。Dan Abramov曾写过一篇关于初步重构的有意义的文章。@EstusFlask,但我将测试从85个减少到67个,并缩短了执行时间。如果测试质量受到影响,这不应该是优先事项。如果目标是减少测试计数,从而减少执行时间,那么您可以像使用_-throwError但不使用它一样,在较少的测试中执行更多断言。至于测试计数,这不一定是件好事。规定了较少的测试报告