首先,要知道单元测试是怎么写的。
下面是一个要测试的函数:
function add(a: number; b: number;) {
return a + b;
}
我们要写单元测试,保证这个函数是OK的:
describe('add', () => {
it('should work', () => {
expect(add(1, 2)).toBe(3);
expect(add(4, 4)).toBe(8);
})
})
如果我们给的测试用例都能通过,那么说明我们的方法是安全可用的。
所以,在你写模块,写函数的时候,如果你的模块,函数,能被很容易的单元测试,那么你写的模块,函数就是80%安全可用的,出现bug的几率很少的。
但是,假如我们把上面的函数改变下:
import { addByRemote } from './api.js';
async function add(a: number; b: number) {
return await addByRemote(a, b);
}
现在这个函数可以很方便的被单元测试吗?答案是不能。因为它依赖了一个接口调用,这个依赖的实现逻辑复杂度是不能确定的,但是我们把它耦合到了我们的add方法里了,那么我们的add方法逻辑就包含了这个接口的逻辑。
我们的add只是个例子,里面的逻辑很简单,但是想像这是个很复杂的业务逻辑,我们要写单元测试,保证这个业务逻辑是OK的,但是因为这个接口调用,我们的业务逻辑变得更复杂更臃肿了。我们的业务逻辑只是依赖这个接口的结果,不想关心接口里面的逻辑的。你如果把这个接口的结果看成函数的参数,就很好理解了。
现在这个 add 函数无法进行单元测试的,因为我们很难模拟这个 http 接口请求,我们可以称这个接口请求为副作用。如果这样的副作用变得多了,那么这个函数变得更加不稳定,更加难于测试了。
那么怎么处理这样的情况呢?
方法1: 把接口的结果作为参数传入我们的函数。
方法2: 通过依赖注入的方式,将这个API注入进去。这样的好处是,我们在单元测试的时候,可以注入一个我们模拟的函数作为这个API。
结论:如果你写的函数,不能很容易的被单元测试,那么你就需要考虑你的函数里面的依赖关系了,否则你写的就是一个很不好的代码。
Top comments (0)