【问题标题】:What is the best approach to unit test node js controller which using a service method使用服务方法单元测试节点 js 控制器的最佳方法是什么
【发布时间】:2018-02-05 20:31:11
【问题描述】:

我的控制器 => 下面的控制器正在使用 reqpoertService.getFiles 方法,并且该方法本身使用外部 API 来调用数据。

function getFiles(req, res) {
    reportService.getFiles({
        fromDate: req.query.fromdate,
        endDate: req.query.enddate,
        fileTypes: req.query.filetypes || [],
        fileStatus: req.query.filestatus || []
    })
    .then(data => {
       logger.info('-> reportService.getFiles :: Successfully fetched data',
                   resolveLogger({ statusCode: res.statusCode })
       );
       res.send(data);
   })
   .catch(err => {
       logger.error('<- OOPS :: reportService.getFiles fail to fetch data');
       res.status(statusCodes.INTERNAL_SERVER_ERROR).send({});
       logger.error('<- ERROR', resolveLogger({
           statusCode: res.statusCode,
           errMessage: err.message,
           errorStack: err
       }));
   });
}

记者服务

function getFiles() {
    return new Promise((resolve, reject) => {
        requestPromise(options)
            .then(data => {
                var duration = new Date - start;
                logger.info(resolveLogger({
                    duration: duration + 'ms',
                    reqUrl: options.url,
                    bodyLengh: data && data.length
                }));
                logger.info('<= Request complete successfully.');
                var resData = JSON.parse(data);
                resolve(resData);
            })
            .catch(error => {
                logger.error('=> Request failed for URL:', options.url);
                reject(error);
            });
    });
}

我的单元测试方法来测试上面的控制器

it('METHOD: getFiles -> should response 500 without data', done => {
    nock('http://localhost:1708/fakeapi')
        .get('/files')
        .reply(statusCodes.INTERNAL_SERVER_ERROR);

    const res = buildResponse();
    const req = httpMocks.createRequest({
        method: 'GET',
        url: '/api/submitted-data/1/files'
    });

    res.on('end', function () {
        var data = res._getData();
        expect(data).toEqual({});
        expect(statusCodes.INTERNAL_SERVER_ERROR).toBe(res.statusCode);
        done();
        nock.cleanAll();
    });

    reporterController.getFiles(req, res);
});

有人可以建议我遵循的方法是可以接受的,还是有更好的方法来进行单元测试。因为我是初学者做单元测试。

【问题讨论】:

    标签: javascript node.js unit-testing jasmine


    【解决方案1】:

    我认为您的方法是正确的。您的测试应该尽可能多地与实现分离。所以你的测试代码不应该真的知道你是如何实现你的代码的。它只关心当您到达端点时,结果是否符合预期。您想模拟代码的外部部分,即在运行测试时不会执行的代码,例如外部 API。您可以模拟外部 API 的某些响应,以便您可以编写测试来涵盖这些类型的场景,然后根据需要处理它们。

    ThoughtWorks 的这篇文章对解释这种测试方法很有帮助:https://www.thoughtworks.com/insights/blog/mockists-are-dead-long-live-classicists

    我还建议观看此视频标题 Ian Cooper:TDD 哪里出了问题:https://vimeo.com/68375232

    感谢我的建议有点高级,所以简而言之,我认为您的测试应该如下所示:

    1. 建立测试上下文、设置数据等。因此,在您的情况下,请确保文件存在(如果来自外部 api,这可能是模拟响应)
    2. 为您的外部 API 设置模拟(以涵盖外部 API 超时、已关闭、401、500 等情况)。
    3. 调用你的 api
    4. 断言您的 api 端点返回的结果

    然后,您可以进行不同的测试来检查外部 api 返回的不同响应。

    【讨论】:

      【解决方案2】:

      我对你的单元测试有一个批评,那就是你没有使用 beforeAll/each 来实际设置你的测试。

      我的意思是:

      • 您可以使用嵌套“it”的描述块来声明将在测试设置期间设置的变量(beforeEach/All),并且应该是您在“it”期间实际“预期”的变量。
      • “它”本身应该更干净、更小,几乎只能由预期组成。

      除此之外它看起来不错。

      【讨论】:

      • 我不同意。特别是,我发现Eric Elliot's arguments 反对 beforeEach 和相关功能非常引人注目且有充分根据。将状态排除在测试之外。通过使用帮助程序并避免所有有状态的废话,您可以保持 DRY。作为奖励,您不会耦合到测试框架及其全局变量。一个名为it 的全局函数坦率地说很恶心。测试应遵循良好的编码习惯。
      • @AluanHaddad 因为问题是关于茉莉花的,所以我认为抱怨它没有任何意义(笑)。关于 beforeEach/All: Yes 状态不应该被共享,但 setup 不属于“it”块。您可以通过使用描述块来避免这种情况,该块将确定您最终将测试的值的范围,并在 beforeAll 中执行您想要测试的任何内容,之后不同的它将充当“期望包”,即期望逻辑上是连在一起的,可以在其描述中表达出来。
      • 老实说,我发现设置例程并没有提供任何真正的好处。它们还需要使用letvar 声明。我更喜欢编写一个返回值的工厂函数。然后我对它使用解构。无论如何,我没有投反对票或其他任何事情,我只是不喜欢编码模式。
      猜你喜欢
      • 1970-01-01
      • 2010-10-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-07-04
      • 1970-01-01
      相关资源
      最近更新 更多