Каков наилучший подход к контроллеру js unit test node, который использует метод обслуживания

My Controller = > ниже контроллер использует метод 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);
            });
    });
}

Мой Unit Test Подход к тестированию выше контроллера

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);
});

Может ли кто-нибудь предложить мне подход, которым я следую, является приемлемым или есть лучший подход к unit test. Поскольку я начинаю выполнять модульное тестирование.

Ответ 1

Я думаю, что ваш подход на правильном пути. Ваши тесты должны быть максимально отстранены от реализации. Таким образом, ваш тестовый код не должен знать, как вы реализовали свой код. Просто важно, что, когда вы нажимаете на свои конечные точки, результат будет таким, как ожидалось. Вы хотите высмеять внешние части вашего кода, то есть код, который не будет выполняться при выполнении вашего теста, например, внешних API. Вы можете высмеять некоторые ответы, которые внешние API, чтобы вы могли писать тесты для покрытия этих типов сценариев, а затем обрабатывать их по своему усмотрению.

Эта статья из ThoughtWorks весьма полезна для объяснения этого подхода к тестированию: https://www.thoughtworks.com/insights/blog/mockists-are-dead-long-live-classicists

Я также предлагаю посмотреть этот видеоролик Ian Cooper: TDD, где все пошло не так: https://vimeo.com/68375232

Я ценю, что мое предложение немного высокого уровня, поэтому, по-моему, ваш тест должен выглядеть следующим образом:

  • установить контекст вашего теста, настроить данные и т.д. Таким образом, в вашем случае убедитесь, что файл существует (это может быть издеваемым ответом при выходе из внешнего api).
  • настроен на издевательство над вашей внешней apis (для покрытия, если время выхода внешнего api отключено, 401, 500 и т.д.).
  • назовите свой api
  • утвердить результат, возвращаемый конечной точкой api

Затем у вас могут быть разные тесты, проверяющие разные ответы, возвращаемые внешним apis.

Ответ 2

У меня есть одна критика вас unit test, и вы не используете beforeAll/each, чтобы на самом деле настроить ваш тест.

Я имею в виду:

  • Вы можете использовать блок описания, в котором "он" вложен, чтобы объявлять переменные, которые будут установлены во время тестовой настройки (beforeEach/All), и должны быть теми, которые вы на самом деле "ожидаете" во время "этого".
  • "Они сами должны быть более чистыми и меньшими, почти только составленными ожиданиями.

Appart от того, что он выглядит хорошо.