[javascript] 다른 모듈이 필요한 node.js 모듈의 단위 테스트 방법



2 Answers

이 경우 더 나은 옵션은 반환 된 모듈의 메소드를 조롱하는 것입니다.

더 좋든 나쁘 든 대부분의 node.js 모듈은 싱글 톤입니다. 동일한 모듈을 요구하는 두 개의 코드 ()는 해당 모듈에 대한 동일한 참조를 얻습니다.

이것을 활용하여 sinon 같은 것을 사용하여 필요한 항목을 조롱 할 수 있습니다. mocha 테스트는 다음과 같습니다.

// in your testfile
var innerLib  = require('./path/to/innerLib');
var underTest = require('./path/to/underTest');
var sinon     = require('sinon');

describe("underTest", function() {
  it("does something", function() {
    sinon.stub(innerLib, 'toCrazyCrap', function() {
      // whatever you would like innerLib.toCrazyCrap to do under test
    });

    underTest();

    sinon.assert.calledOnce(innerLib.toCrazyCrap); // sinon assertion

    innerLib.toCrazyCrap.restore(); // restore original functionality
  });
});

Sinon은 주장을 만드는 데있어 chai와통합되어 있으며 sinon과 mocha통합 하여 모듈 스파이 / 스텁 정리 (테스트 오염을 방지 할 수 있습니다.)를 작성했습니다.

underTest는 함수 만 반환하기 때문에 underTest는 같은 방식으로 조롱 될 수 없습니다.

Question

이것은 내 문제의 핵심을 보여주는 간단한 예입니다.

var innerLib = require('./path/to/innerLib');

function underTest() {
    return innerLib.doComplexStuff();
}

module.exports = underTest;

이 코드에 대한 단위 테스트를 작성하려고합니다. require 함수를 완전히 조롱하지 않고 어떻게 innerLib 대한 요구 사항을 조롱 할 수 있습니까?

편집 : 그래서 이것은 세계적인 욕구를 모의하려고 노력하고 그것을 할 수 없다는 것을 알아내는 것입니다 :

var path = require('path'),
    vm = require('vm'),
    fs = require('fs'),
    indexPath = path.join(__dirname, './underTest');

var globalRequire = require;
require = function(name) {
    console.log('require: ' + name);
    switch(name) {
        case 'connect':
        case indexPath:
            return globalRequire(name);
            break;
    }
};

문제는 underTest.js 파일의 require 함수가 실제로 조롱되지 않았다는 것입니다. 글로벌 require 기능을 여전히 가리 킵니다. 그래서 나는 조롱을하고있는 동일한 파일 내에서 require 함수를 조롱 할 수있는 것처럼 보입니다. 전역 require 에 아무것도 포함시키지 않으면 로컬 복사본을 재정의 한 후에도 필요한 파일에 전역 require 참조가 계속 유지됩니다.




mockery 라이브러리를 사용할 수 있습니다 :

describe 'UnderTest', ->
  before ->
    mockery.enable( warnOnUnregistered: false )
    mockery.registerMock('./path/to/innerLib', { doComplexStuff: -> 'Complex result' })
    @underTest = require('./path/to/underTest')

  it 'should compute complex value', ->
    expect(@underTest()).to.eq 'Complex result'



조롱 require 는 나에게 거친 해킹처럼 느껴진다. 필자는 개인적으로 코드를 피하고 코드를 리팩터링하여 더 테스트 할 수있게하려고 노력할 것입니다. 종속성을 처리하는 데는 여러 가지 방법이 있습니다.

1) 인자로서 의존성 전달

function underTest(innerLib) {
    return innerLib.doComplexStuff();
}

이렇게하면 코드를 보편적으로 테스트 할 수 있습니다. 단점은 주변에 의존성을 전달해야하므로 코드가 복잡해질 수 있다는 것입니다.

2) 모듈을 클래스로 구현 한 다음 클래스 메서드 / 속성을 사용하여 종속성 얻기

(이것은 인위적인 예이며, 클래스 사용은 합리적이지 않지만 아이디어를 전달합니다) (ES6 예제)

const innerLib = require('./path/to/innerLib')

class underTestClass {
    getInnerLib () {
        return innerLib
    }

    underTestMethod () {
        return this.getInnerLib().doComplexStuff()
    }
}

이제 getInnerLib 메소드를 쉽게 스텁하여 코드를 테스트 할 수 있습니다. 이 코드는보다 자세한 정보가 될뿐만 아니라 테스트하기도 쉽습니다.



Related