Typescript / Node.js - как имитировать транзитивные зависимости для интеграционного тестирования?

Скажем, у меня есть экспресс-маршрут, который обрабатывается контроллером. Контроллер использует службу, а служба использует репозиторий для взаимодействия с источником данных.

Я хочу создать интеграционный тест, используя Supertest, чтобы проверить этот маршрут:

test -> my Express app -> controller -> service -> repository -> data source

Моя проблема в том, что мне нужно имитировать репозиторий / источник данных, чтобы запустить тест! Я хочу жестко закодировать некоторые значения, как если бы они поступали из реального источника данных. Какие у меня варианты?

В мире Java я бы использовал инъекцию зависимостей с помощью Spring или Guice, и таким образом я бы заменил репозиторий на макетную версию. Каковы шаблоны для достижения такого рода насмешек в мире Typescript / Node.js?

Я предполагаю, что, используя простой Javascript, я мог бы использовать Proxyquire и его функцию глобально переопределить требование, чтобы макет репозитория из самого теста. Но я не уверен, что это хорошо работает с Typescript.

Итак, каковы рекомендуемые способы имитации «глубокого» компонента (транзитивной зависимости) из тестового файла с помощью Typescript и Node.js?


person electrotype    schedule 27.02.2017    source источник
comment
Если вы используете простой узел, а не Typescript, есть прекрасная библиотека от создателя паспорта под названием electrolyte. который выполняет инъекцию зависимостей / IoC. Вы настраиваете папки, которые он будет искать в обратном порядке, используя свою функцию IoC.use(..), поэтому в моем тестовом файле начальной загрузки я добавляю свои папки макетов, чтобы он сначала смотрел туда, и разрешил мой источник фиктивных данных вместо источника данных в моем другом папки или модули узлов.   -  person Liam Gray    schedule 28.02.2017
comment
Я создал библиотеку тестирования для Typescript, которая упрощает имитацию зависимостей, независимо от того, где они находятся в цепочке зависимостей: ts-mock-import   -  person EmandM    schedule 09.07.2018


Ответы (1)


Модули кэшируются после первой загрузки, поэтому вы можете просто сначала загрузить их в свой тестовый файл и заглушить их, используя такую ​​библиотеку, как sinon.

Рассмотрим следующий код:

// dependency.ts
export function foo(){
    return 'foo';
}

// app.ts
import {foo} from './dependency';
export default function main(){
    return  'winner ' + foo();
}

Вы можете протестировать app.ts, заглушив его зависимость от sinon, следующим образом:

import * as Dependency from '../src/dependency';
import main from '../src/app';

describe('test dependency', () => {
    var fooStub;
    beforeEach(() => {
        fooStub = sinon.stub(Dependency, 'foo');
        fooStub.returns('la la lang');
    });
    afterEach(()=>{
        fooStub.restore();
    })

    it('uses stubbed dependency', ()=>{
        expect(main()).to.be.equal('winner la la lang');
    });

    it('can return different values on other tests', ()=>{
        fooStub.returns('moonlight');
        expect(main()).to.be.equal('winner moonlight');
    });
});

Итак, в основном для ваших интеграционных тестов вы можете импортировать и заглушить свои зависимости перед запуском приложения. Я сделал это, создав app.proxy.ts файл:

  • В app.proxy импортируйте свой репозиторий и заглушите его, чтобы вернуть предопределенные данные. После настройки заглушки импортируйте реальный app.ts и экспортируйте его.
  • В файле теста интеграции импортируйте app.proxy вместо app и используйте его с supertest. Это даст вам приложение в конце, но после настройки заглушенной зависимости!
  • напишите и запустите тест, зная, что он будет использовать предопределенные данные
person Daniel J.G.    schedule 28.02.2017