如何测试调用多个其他函数的函数?
How to test function calling multiple other functions?
我正在编写一个 ExpressJS 中间件,它稍微修改请求对象并检查用户是否可以访问该特定页面。我对它进行单元测试有问题。我已经为每个方法编写了单独的测试,除了一个:handler
。如何测试 handler
功能?我应该测试一下吗?或者我应该用 istanbul ignore next
忽略它,因为我已经涵盖了所有其他功能?或者也许我应该以某种方式重写我的 handler
函数以使其可测试?
class Example {
constructor(request, response, next, userAccountService) {
this.req = request;
this.res = response;
this.next = next;
this.userAccountService = userAccountService;
}
removeTokenFromQuery() {
delete this.req.query.token;
}
isValidRequest() {
if (!this.req.secure) {
return false;
}
if (typeof this.req.query.token !== 'undefined') {
return false;
}
if (typeof this.req.query.unsupportedQueryParam !== 'undefined') {
return false;
}
return true;
}
isPageAccessibleForUser() {
return this.userAccountService.hasAccess('example');
}
async handler() {
this.removeTokenFromQuery();
if (!this.isValidRequest()) {
throw new Error('Invalid request');
}
if (!this.isPageAccessibleForUser()) {
this.res.statusCode(500);
this.res.end();
return;
}
this.next();
}
}
然后它被称为 Express 中间件:
this.app.use((res, req, next) => {
const exampleObj = new Example(res, req, next, userAccServ);
exampleObj.handler();
});
我应该测试一下吗?
是的,根据您的示例处理程序包含(看起来是)一些关键业务逻辑。它负责编排:
- 从请求中删除令牌(安全)
- 确定请求是否有效 (security/auth)
- 确定页面是否可供用户访问 (security/auth)
如果这个功能没有经过测试,未来的工程师可能会修改这个重要的功能,他们不会收到任何关于他们的更改的反馈。假设由于人为错误,他们不小心删除了 isValidRequest 检查?或删除 !
。然而,与测试这一点所需的相对较少的努力相比,与这种情况相关的风险可能是灾难性的。
如何测试处理函数?
下一个问题是你如何实际测试这个:)我会选择在最低 "level" 可能的 lower 上测试这个(单元通过调用它来测试这个方法直接 vs higher(通过 express 框架)。
正如您提到的,handler
委托给每个功能的实现都有测试,IMO handler
中要测试的重要事情是流程而不是实现(因为这些已经过良好测试)。
describe('handler()', () => {
it('removes token from query');
it('errors on invalid request');
it('returns 500 status code when page is inaccessible');
it('continues with .next() when request is valid and page is accessible');
})
为了做到这一点,我将实例化 Example
,然后修补必要的方法,以便为您的 handler()
测试创建正确的流程。所以对于无效请求测试,这可能看起来像:
const example = new Example();
sinon.stub(example, "isValidRequest").returns(false);
如果这没有存根,那么这些测试基本上会重复其他测试(通过测试实际实现)。使用存根允许 isValidRequest
的实现发生变化,同时在 handler
中仍然具有单元测试保护
我正在编写一个 ExpressJS 中间件,它稍微修改请求对象并检查用户是否可以访问该特定页面。我对它进行单元测试有问题。我已经为每个方法编写了单独的测试,除了一个:handler
。如何测试 handler
功能?我应该测试一下吗?或者我应该用 istanbul ignore next
忽略它,因为我已经涵盖了所有其他功能?或者也许我应该以某种方式重写我的 handler
函数以使其可测试?
class Example {
constructor(request, response, next, userAccountService) {
this.req = request;
this.res = response;
this.next = next;
this.userAccountService = userAccountService;
}
removeTokenFromQuery() {
delete this.req.query.token;
}
isValidRequest() {
if (!this.req.secure) {
return false;
}
if (typeof this.req.query.token !== 'undefined') {
return false;
}
if (typeof this.req.query.unsupportedQueryParam !== 'undefined') {
return false;
}
return true;
}
isPageAccessibleForUser() {
return this.userAccountService.hasAccess('example');
}
async handler() {
this.removeTokenFromQuery();
if (!this.isValidRequest()) {
throw new Error('Invalid request');
}
if (!this.isPageAccessibleForUser()) {
this.res.statusCode(500);
this.res.end();
return;
}
this.next();
}
}
然后它被称为 Express 中间件:
this.app.use((res, req, next) => {
const exampleObj = new Example(res, req, next, userAccServ);
exampleObj.handler();
});
我应该测试一下吗?
是的,根据您的示例处理程序包含(看起来是)一些关键业务逻辑。它负责编排:
- 从请求中删除令牌(安全)
- 确定请求是否有效 (security/auth)
- 确定页面是否可供用户访问 (security/auth)
如果这个功能没有经过测试,未来的工程师可能会修改这个重要的功能,他们不会收到任何关于他们的更改的反馈。假设由于人为错误,他们不小心删除了 isValidRequest 检查?或删除 !
。然而,与测试这一点所需的相对较少的努力相比,与这种情况相关的风险可能是灾难性的。
如何测试处理函数?
下一个问题是你如何实际测试这个:)我会选择在最低 "level" 可能的 lower 上测试这个(单元通过调用它来测试这个方法直接 vs higher(通过 express 框架)。
正如您提到的,handler
委托给每个功能的实现都有测试,IMO handler
中要测试的重要事情是流程而不是实现(因为这些已经过良好测试)。
describe('handler()', () => {
it('removes token from query');
it('errors on invalid request');
it('returns 500 status code when page is inaccessible');
it('continues with .next() when request is valid and page is accessible');
})
为了做到这一点,我将实例化 Example
,然后修补必要的方法,以便为您的 handler()
测试创建正确的流程。所以对于无效请求测试,这可能看起来像:
const example = new Example();
sinon.stub(example, "isValidRequest").returns(false);
如果这没有存根,那么这些测试基本上会重复其他测试(通过测试实际实现)。使用存根允许 isValidRequest
的实现发生变化,同时在 handler