如何测试调用多个其他函数的函数?

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

中仍然具有单元测试保护