ES6 모듈의 수입을 조롱하는 방법?
다음과 같은 ES6 모듈이 있습니다.
network.js
export function getDataFromServer() {
return ...
}
widget.js
import { getDataFromServer } from 'network.js';
export class Widget() {
constructor() {
getDataFromServer("dataForWidget")
.then(data => this.render(data));
}
render() {
...
}
}
의 모의 인스턴스로 위젯을 테스트하는 방법을 찾고 getDataFromServer
있습니다. <script>
Karma와 같이 ES6 모듈 대신 별도 의 s를 사용하면 다음 과 같이 테스트를 작성할 수 있습니다.
describe("widget", function() {
it("should do stuff", function() {
let getDataFromServer = spyOn(window, "getDataFromServer").andReturn("mockData")
let widget = new Widget();
expect(getDataFromServer).toHaveBeenCalledWith("dataForWidget");
expect(otherStuff).toHaveHappened();
});
});
그러나 브라우저 외부에서 개별적으로 ES6 모듈을 테스트하는 경우 (Mocha + babel과 같은) 다음과 같이 작성합니다.
import { Widget } from 'widget.js';
describe("widget", function() {
it("should do stuff", function() {
let getDataFromServer = spyOn(?????) // How to mock?
.andReturn("mockData")
let widget = new Widget();
expect(getDataFromServer).toHaveBeenCalledWith("dataForWidget");
expect(otherStuff).toHaveHappened();
});
});
좋아, 그러나 지금 getDataFromServer
은 사용할 수 window
없으며 (아무도 없다 window
), 나는 물건을 widget.js
자신의 범위에 직접 주입하는 방법을 모른다 .
여기서 어디로 가야합니까?
- 의 범위에 액세스
widget.js
하거나 가져 오기를 내 코드로 바꾸는 방법이 있습니까? - 그렇지 않다면 어떻게
Widget
테스트 할 수 있습니까?
내가 고려한 것들 :
ㅏ. 수동 의존성 주입.
모든 가져 오기를 제거 widget.js
하고 발신자가 뎁스를 제공 할 것으로 예상합니다.
export class Widget() {
constructor(deps) {
deps.getDataFromServer("dataForWidget")
.then(data => this.render(data));
}
}
위젯의 공용 인터페이스를 엉망으로 만들고 구현 세부 정보를 노출하는 것이 매우 불편합니다. 안돼
비. 수입품을 조롱 할 수 있도록 노출하십시오.
다음과 같은 것 :
import { getDataFromServer } from 'network.js';
export let deps = {
getDataFromServer
};
export class Widget() {
constructor() {
deps.getDataFromServer("dataForWidget")
.then(data => this.render(data));
}
}
그때:
import { Widget, deps } from 'widget.js';
describe("widget", function() {
it("should do stuff", function() {
let getDataFromServer = spyOn(deps.getDataFromServer) // !
.andReturn("mockData");
let widget = new Widget();
expect(getDataFromServer).toHaveBeenCalledWith("dataForWidget");
expect(otherStuff).toHaveHappened();
});
});
이것은 덜 침습적이지만 각 모듈에 대해 많은 상용구를 작성해야하며 항상 getDataFromServer
대신 사용하는 위험 deps.getDataFromServer
이 있습니다. 나는 그것에 대해 불안하지만 그것이 지금까지 나의 최고의 아이디어입니다.
I've started employing the import * as obj
style within my tests, which imports all exports from a module as properties of an object which can then be mocked. I find this to be a lot cleaner than using something like rewire or proxyquire or any similar technique. I've done this most often when needing to mock Redux actions, for example. Here's what I might use for your example above:
import * as network from 'network.js';
describe("widget", function() {
it("should do stuff", function() {
let getDataFromServer = spyOn(network, "getDataFromServer").andReturn("mockData")
let widget = new Widget();
expect(getDataFromServer).toHaveBeenCalledWith("dataForWidget");
expect(otherStuff).toHaveHappened();
});
});
If your function happens to be a default export, then import * as network from './network'
would produce {default: getDataFromServer}
and you can mock network.default.
@carpeliam is correct but note that if you want to spy on a function in a module and use another function in that module calling that function, you need to call that function as part of the exports namespace otherwise the spy won't be used.
Wrong example:
// mymodule.js
export function myfunc2() {return 2;}
export function myfunc1() {return myfunc2();}
// tests.js
import * as mymodule
describe('tests', () => {
beforeEach(() => {
spyOn(mymodule, 'myfunc2').and.returnValue = 3;
});
it('calls myfunc2', () => {
let out = mymodule.myfunc1();
// out will still be 2
});
});
Right example:
export function myfunc2() {return 2;}
export function myfunc1() {return exports.myfunc2();}
// tests.js
import * as mymodule
describe('tests', () => {
beforeEach(() => {
spyOn(mymodule, 'myfunc2').and.returnValue = 3;
});
it('calls myfunc2', () => {
let out = mymodule.myfunc1();
// out will be 3 which is what you expect
});
});
@vdloo's answer got me headed in the right direction, but using both commonjs "exports" and ES6 module "export" keywords together in the same file did not work for me (webpack v2 or later complains). Instead, I'm using a default (named variable) export wrapping all of the individual named module exports and then importing the default export in my tests file. I'm using the following export setup with mocha/sinon and stubbing works fine without needing rewire, etc.:
// MyModule.js
let MyModule;
export function myfunc2() { return 2; }
export function myfunc1() { return MyModule.myfunc2(); }
export default MyModule = {
myfunc1,
myfunc2
}
// tests.js
import MyModule from './MyModule'
describe('MyModule', () => {
const sandbox = sinon.sandbox.create();
beforeEach(() => {
sandbox.stub(MyModule, 'myfunc2').returns(4);
});
afterEach(() => {
sandbox.restore();
});
it('myfunc1 is a proxy for myfunc2', () => {
expect(MyModule.myfunc1()).to.eql(4);
});
});
I implemented a library that attempts to solve the issue of run-time mocking of Typescript class imports without needing the original class to know about any explicit dependency injection.
The library uses the import * as
syntax and then replaces the original exported object with a stub class. It retains type safety so your tests will break at compile time if a method name has been updated without updating the corresponding test.
This library can be found here: ts-mock-imports.
I have found this syntax to be working:
My module:
// mymod.js
import shortid from 'shortid';
const myfunc = () => shortid();
export default myfunc;
My module's test code:
// mymod.test.js
import myfunc from './mymod';
import shortid from 'shortid';
jest.mock('shortid');
describe('mocks shortid', () => {
it('works', () => {
shortid.mockImplementation(() => 1);
expect(myfunc()).toEqual(1);
});
});
See the doc.
참고URL : https://stackoverflow.com/questions/35240469/how-to-mock-the-imports-of-an-es6-module
'Programing' 카테고리의 다른 글
JVM과 HotSpot의 차이점은 무엇입니까? (0) | 2020.06.30 |
---|---|
최고의 오픈 소스 Java 차트 라이브러리는 무엇입니까? (0) | 2020.06.30 |
URL에서 JSON 객체 가져 오기 (0) | 2020.06.29 |
하나 이상의 공백 또는 탭으로 문자열 분해 (0) | 2020.06.29 |
EF Core를 사용하여 ASP.NET Core에서 마이그레이션을 적용 취소하는 방법 (0) | 2020.06.29 |