๊ธฐ๋ฅ ์ ์์ฒญํ๊ฑฐ๋ ๋ฒ๊ทธ๋ฅผ ๋ณด๊ณ ํ์๊ฒ ์ต๋๊น?
๋ฒ๋
ํ์ฌ ํ๋์ ๋ฌด์์ ๋๊น?
test
๋๋ it
๋ด๋ถ์์ ํฉํ ๋ฆฌ๋ก mock์ ์์ฑํ๋ ๋ฐฉ๋ฒ์ด ์๋ํ์ง ์๋ ๊ฒ ๊ฐ์ต๋๋ค. ๋ชจ์ ๊ฐ์ฒด๊ฐ ํ์ผ์ ๋ฃจํธ ์์ค์์ ์ ์๋ ๊ฒฝ์ฐ์๋ง ์๋ํฉ๋๋ค.
๋ค์์ ๋ชจ์ ์์ ๋๋ค.
jest.mock('services/feature', () => ({
isEnabled: () => true
}));
์์๋๋ ๋์์ ๋ฌด์์ ๋๊น?
ํ ์คํธ ๋ด์์ ํ์ผ์ ์กฐ๋กฑํ๋ฉด ์๋ํฉ๋๋ค.
์ ํํ Jest ๊ตฌ์ฑ์ ์ ๊ณตํ๊ณ Jest, ๋ ธ๋, yarn/npm ๋ฒ์ ๋ฐ ์ด์ ์ฒด์ ๋ฅผ ์ธ๊ธํ์ญ์์ค.
Jest 18.0.0, ๋ ธ๋ 7.4, macOS
jest.mock
ํธ์ถ์ babel-jest ๋ณํ์ ์ฌ์ฉํ์ฌ ํ์ผ์ ๋งจ ์๋ก ์๋์ผ๋ก ํธ์ด์คํธ๋ฉ๋๋ค. jest.doMock
ํ์ฌ ์ด ๋์์ ์๋ตํ ์ ์์ต๋๋ค. ๋น์ ์ ๊ทธ๊ฒ์ ์๋ ํ์ต๋๊น?
doMock
์
๋๋ค.
๋ฌธ์์์ ์ฝ์ ์ ์์ต๋๋ค
์ฐธ๊ณ :
babel-jest
์ฌ์ฉํ ๋ mock์ ๋ํ ํธ์ถ์ ์๋์ผ๋ก ์ฝ๋ ๋ธ๋ก์ ๋งจ ์๋ก ์ฌ๋ผ๊ฐ๋๋ค. ์ด ๋์์ ๋ช ์์ ์ผ๋ก ํผํ๋ ค๋ฉดdoMock
์ฌ์ฉํ์ญ์์ค.
ํ์ง๋ง... ํ ์คํธ๋ ์ฝ๋ ๋ธ๋ก์ด์ฃ ? ๊ทธ๋์ ์ ๊ฒฝ์ฐ์๋ ์ด๋ค ์ฐจ์ด์ ๋ ๊ธฐ๋ํ์ง ์์ต๋๋ค.
๋ค์์ ์ ์ฒด ํ ์คํธ์ ๋๋ค.
it('renders with the enabled feature', () => {
jest.mock('services/feature', () => ({
isEnabled: () => true
}));
const component = renderer.create(
<MyComponent />
);
const tree = component.toJSON();
expect(tree).toMatchSnapshot();
});
GH ์ ์ฅ์์์ ์ด์ ๋ํ ์ฌํ์ ์ ๊ณตํ ์ ์์ต๋๊น?
ํ์ ํ๋. ์ฌ๊ธฐ ์์ต๋๋ค: https://github.com/tleunen/jest-issue-2582
๋ ํ
์คํธ ์ค ํ๋์ "ํ์ฑํ๋จ"์ ๋ ๋๋งํ๋ ๋ชจ์๊ฐ ์์ง๋ง ๋ ํ
์คํธ ๋ชจ๋ "๋นํ์ฑํ๋จ"์ผ๋ก ๋ ๋๋ง๋ฉ๋๋ค.
๋ค์์ ์ฐธ์กฐํ์ญ์์ค.
https://github.com/tleunen/jest-issue-2582/blob/master/src/MyComponent.js
https://github.com/tleunen/jest-issue-2582/blob/master/src/__tests__/MyComponent.spec.js
๊ฐ์ฌ ํด์.
์ด ๋ฌธ์ ์ ๋ํด @thymikee @cpojer์ ๋ํ ์กฐ์ธ์ด ์์ต๋๊น?
๋์ผํ ํ์ผ์ ์ฌ๋ฌ ํ
์คํธ๊ฐ ์๊ณ ๊ฐ๊ฐ์ ๋ํด ๋ค๋ฅธ ๋ชจ์ ์๋ต์ ๊ฐ๊ณ ์ถ์ต๋๋ค.
์ด ๋ฌธ์ ๋ฅผ ๋ฐ๊ฒฌํด์ ๋คํ์
๋๋ค. ์ jest.mock()
๊ฐ describe
๋ฒ์์์ ์๋ํ์ง ์๋์ง ๋จธ๋ฆฌ๊ฐ ์ํ ์ต๋๋ค. ์๋จ(ํ
์คํธ ํ์ผ์์ ๋ด ๊ฐ์ ธ์ค๊ธฐ ์๋)์ผ๋ก ์ด๋ํ๋ฉด ์๋ํฉ๋๋ค.
๋๋ฅผ ์ํด ๊ทธ๊ฒ์ ๋ํ ์กฐ๋กฑ๋ ํ์ผ์ ํฌํจํ๋ __mocks__
ํด๋๋ฅผ ์ฌ์ฉํ์ฌ ๊ณต์ฅ ์์ด jest.mock()
์ ์ฉ๋ฉ๋๋ค.
--ํธ์งํ๋ค
jest.mock()
๋ฌธ์ import ๋ฌธ ์์ ์ฌ๋ ค๋๋ ๊ฒ์ ๋ถ๋ช
ํ ํ์ํฉ๋๋ค. ๊ทธ๋ฌ๋ @tleunen , ์ด๊ฒ์ ์๋ง๋ ๋ค๋ฅธ ์๋ต์ผ๋ก ๋์ผํ ํ์ผ์ ๋ ๋ฒ ์ด์ ์กฐ๋กฑํ๋ ๊ฒ์ด ๋ถ๊ฐ๋ฅํ๋ค๋ ๊ฒ์ ์๋ฏธํฉ๋๋ค. ํฉํ ๋ฆฌ ๊ธฐ๋ฅ์ ๋ณด๋ค ๋์ ์ผ๋ก ๋ง๋ค์ด ๊ฐ ํ
์คํธ ์ผ์ด์ค์์ ๋ค๋ฅธ ๊ฒฐ๊ณผ๋ฅผ ์ ๊ณตํ ์ ์์ต๋๋ค.
๋ด ์๊ฐ์๋ jest.mock()
๊ฐ ํญ์ describe
๋ฐ it
๋ธ๋ก ์ธ๋ถ์ ์์ผ๋ฉด ๋ ๋ช
ํํด์ง ๊ฒ์
๋๋ค. ๊ทธ๋ฌ๋ ์ด๊ฒ์ ๋ฌธ์์ ๋ช
ํํ๊ฒ ๋ช
์๋์ด์ผ ํฉ๋๋ค.
๋ฐ๋ผ์ jest.mock
๋ ํจ์ ๋ฒ์๋ก ํธ์ด์คํธ๋๊ณ ์์ผ๋ฏ๋ก require
s(๊ทธ๋ฆฌ๊ณ ํ์คํ ๋ชจ๋ ๋ฒ์๋ก ํธ์ด์คํธ๋๋ import
s๊ฐ ์๋)์ ํจ๊ป ์๋ํ์ง ์๋ ์ด์ ๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค. describe
(Jasmine์ ์ํด ํน๋ณํ ์ฒ๋ฆฌ๋จ) ์ด์ธ์ ํจ์ ๋ด์์ ํธ์ถํฉ๋๋ค.
jest.mock
ํธ์ถ์ ๋ฐ๋ก ๊ทธ ํจ์(๋ชจ๋์ด ์๋)์ ๋งจ ์๋ก ํธ์ด์คํธ๋๋ฏ๋ก ์์๋๋ก ์๋ํ์ง ์์ต๋๋ค.
์ผ๋ฐ์ ์ผ๋ก ํ
์คํธ ์ผ์ด์ค์์ ์๋ก ๋ค๋ฅด๊ฒ ํ๋ ค๋ฉด beforeEach
๋ฐ afterEach
์๋ก ๋ค๋ฅธ ๋ชจ์๋ฅผ ์ค์ ํ๋ ๊ฒ์ด ์ข์ต๋๋ค.
@cpojer ๋ ์ด์ ๋ํด ์์ธํ ์ค๋ช ํ ์ ์์ผ๋ฉฐ ์์ ๋ฒ์์ ๋ํ ํธ์ถ์ ํธ์ด์คํธํ๋ ค๋ ๊ฒฝ์ฐ์ ๋๋ค.
๋ชจ๋์ด ์ด๊ธฐํ๋ ๋(๊ฐ์ ธ์ค๊ธฐ ์ฌ์ฉ) ๋ชจ๋์ด ํ์ํ๊ธฐ ๋๋ฌธ์
๋๋ค. jest.mock
๋ ๋์ค์ ํธ์ถ๋ฉ๋๋ค. ์ด๋ฅผ ํด๊ฒฐํ๋ ๋ฐฉ๋ฒ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
beforeEach(() => { // or the specific test
jest.mock('MyModule', () => โฆ);
const MyModule = require('MyModule');
โฆ
});
๋ฑ.
beforeEach์์ ์ด ์์ ์ ์ํํ๋ค๋ฉด ํ ์คํธ๋ฅผ ์ด๋ป๊ฒ ๊ตฌ๋ถํ ์ง ์ ๋ชจ๋ฅด๊ฒ ์ต๋๋ค(๊ทธ๋์ ๊ฐ ํ ์คํธ์ ๋ํด ๋ค๋ฅธ ๋ชจ์๋ฅผ ์ ๊ณตํ๋ ๋ฐฉ๋ฒ์ ๋ฌด์์ ๋๊น?)
ํ ์คํธ ์์ฒด์ ๋ฃ๋ ๊ฒ์ ๋ฌผ๋ก ์๋ํฉ๋๋ค.
๊ทธ๋ฐ ๋ค์ ํ ์คํธ๋ ๊ตฌ์ฑ ์์ ๋ด๋ถ์ ๋ชจ์ ๋ชจ๋์ ์ ๋ฌํ ์ ์์ต๋๊น?
์กฐ๋กฑํ๋ ค๋ ํ์ผ(์: ๊ฐ์ ธ์ค๊ณ ์๋ ๋ค๋ฅธ ํ์ผ์ ์ข ์์ฑ)์ ๊ฐ์ ธ์ค๊ฑฐ๋ ํ์๋ก ํ์ง ์์ง๋ง ๋ฒ์๊ฐ describe/it ๋ธ๋ก์ผ๋ก ์ง์ ๋๊ธฐ๋ฅผ ์ํ๋ฉด ์ด๋ป๊ฒ ํฉ๋๊น? ๋๋ beforeEach/beforeAll ํ ์คํธ์ ๋ํด ๋ค๋ฅด๊ฒ ์กฐ๋กฑํ๊ณ ์ถ์ด๋? ๊ทธ๋ฐ ๊ฒฝ์ฐ๊ฐ ๊ฐ๋ฅํ๊ฐ์?
// A.js depends on B.js
import A from './A';
describe('myTest', () => {
describe('myFirstScope', () => {
beforeAll(() => {
jest.mock('./B', () => ({
myFirstMethod: jest.fn(),
}));
});
// tests here
});
describe('mySecondScope', () => {
beforeAll(() => {
jest.mock('./B', () => ({
mySecondMethod: jest.fn(),
}));
});
// tests here
});
});
์ด ๊ฒฝ์ฐ B๋ฅผ ์กฐ๋กฑํ ํ A๊ฐ ํ์ํฉ๋๋ค. ( import
์ฌ์ฉํ์ง ์๊ณ require
).
B๋ฅผ ์กฐ๋กฑํ ํ A ํ์
๋๋ฅผ ์ํด ์ผํ์ง ์์๊ณ ์ฌ์ ํ B์ ์๋ ๋ชจ์๊ฐ ๊ฒฐ๊ณผ๋ก ์ ๋ฌ๋๋ ๊ฒ์๋ณด๊ณ ์์์ต๋๋ค.
@GoldAnna ์ด ๋ฌธ์ ์ ๋ํ ํด๊ฒฐ ๋ฐฉ๋ฒ์ ์ฐพ์์ต๋๊น?
@alayor ๋๋ํ์ง ์์๋ค
์ด ๋ฌธ์ ์ ์ฌ๋ฌ ๋ฒ ๋ถ๋ช์ณค์ง๋ง ์ด์ ๋ ์ ๋๋ก ํ
์คํธํ์ง ์๊ฑฐ๋ ์์ฑ์๊ฐ ์๋ํ ๋๋ก jest
๋ฅผ ์ฌ์ฉํ์ง ์๊ฑฐ๋ ๋ ๊ฐ์ง๋ฅผ ์กฐํฉํ ๊ฒ์ด๋ผ๊ณ ํ์ ํฉ๋๋ค. ์ถ๊ฐ ์ฆ๊ฑฐ๋ jest
์ ๋ฌธ์์ ์๋ ๋ชจ์ ๊ด๋ จ ์์ ์ค ๊ฑฐ์ ๋์๊ฒ ์ค์ ์์ ์ฒ๋ผ ๋ณด์ด์ง ์๋๋ค๋ ๊ฒ์
๋๋ค.
์ฆ, ๋ค์์ ์ ์๊ฒ ํจ๊ณผ์ ์ด๋ฉฐ ๋ค์ ํ
์คํธ๋ ๋ชจ๋ ํต๊ณผํฉ๋๋ค. ModuleB
์ ์๋ ๋ฒ์ ์ผ๋ก ๋์๊ฐ๋ ค๋ฉด jest.resetModules()
๋ฐ jest.unmock('./moduleB')
...๋ฅผ ๋ชจ๋ ํธ์ถํด์ผ ํฉ๋๋ค. ์์๋ ์ค์ํ์ง ์์ต๋๋ค.
// Module A
const ModuleB = require('./moduleB');
const ModuleA = function() {
this.title = new ModuleB().title;
return this;
};
module.exports = ModuleA;
// Module B
const ModuleB = function() {
this.title = 'Module B - Original'
return this;
};
module.exports = ModuleB;
// Tests
describe('Jest a few tests', () => {
it('should do something', () => {
jest.resetModules();
jest.mock('./moduleB', () => function() {
this.title = 'Module B - Mock 1'
return this;
});
const ModuleA = require('./moduleA');
const moduleA = new ModuleA();
expect(moduleA.title).toEqual('Module B - Mock 1');
});
it('should do something else', () => {
jest.resetModules();
jest.mock('./moduleB', () => function() {
this.title = 'Module B - Mock 2'
return this;
});
const ModuleA = require('./moduleA');
const moduleA = new ModuleA();
expect(moduleA.title).toEqual('Module B - Mock 2');
});
it('should do something original', () => {
jest.resetModules();
jest.unmock('./moduleB');
const ModuleA = require('./moduleA');
const moduleA = new ModuleA();
expect(moduleA.title).toEqual('Module B - Original');
});
});
์ด๋ด,
์ฌ๊ธฐ์๋ ์๋ฌด ๊ฒ๋ ์๋ํ์ง ์์ต๋๋ค.
๋๊ตฐ๊ฐ jest.mock์ ๋ด๋ถ์์ ์ฌ์ฉํ ์ ์๋ ์ด์ ๋ฅผ ์ค๋ช
ํด ์ฃผ์๊ฒ ์ต๋๊น?
๊ฐ์ฌํฉ๋๋ค
๋๋ ์ด๊ฒ์ด ์ฌ์ ํ ๊ธฐ๋ฅ ์์ฒญ์ผ๋ก ๋ค์ ์ด๋ ค์ผ ํ๋ ๋ฌธ์ ๋ผ๊ณ ์๊ฐํฉ๋๋ค. ํ ์คํธ๋ฅผ ๋ฐ๋ก ์์ฑํ๊ณ ์ถ์ต๋๋ค. ๋ชจ์ ํด๋์ ๋ฌผ๊ฑด์ ๋ฒ๋ฆฌ๊ฑฐ๋ beforeEach๋ก ๋ค์ ๋ฐฐ์ ํ๋ฉด ์ผ๋ฐ์ ์ผ๋ก ๋ชจ๋ ํ ์คํธ์ ํฌํจ๋๋ ๋ชจ์/์ด์ํ ๋ฐ์ดํฐ ์ธ์คํด์คํ์ ์ ํฌ ์๋์ผ๋ก ๋๋ฉ๋๋ค. ๋๋ ์์ ๋ชจ์๋ฅผ ์์ฑํ๊ณ ์์ ํ ์คํธ๋ฅผ ํต๊ณผํ๊ณ ์ถ์ต๋๋ค.
๊ฐ๋ณ ํ
์คํธ๋ฅผ ๊ฒฉ๋ฆฌํ๋ ์ค์ ๋ฐฉ๋ฒ์ ์์ต๋๋ค( test.concurrent
). ํญ์ด๋ ava์ ์ ์ฌํ API๋ฅผ ์ฑํํ๋ค๋ฉด ๊ฐ๋ฅํ๊ฒ ์ง๋ง ํ์ฌ ๊ธ๋ก๋ฒ API๊ฐ ๋ถ๊ณผํ๋ ์ ์ฝ ์กฐ๊ฑด์ผ๋ก๋ ๋ถ๊ฐ๋ฅํ๋ค๊ณ ์๊ฐํฉ๋๋ค. ์๋ชป๋ ๊ฒ์ผ๋ก ํ๋ช
๋์ด ๋งค์ฐ ๊ธฐ์ฉ๋๋ค!
์ด์ ์ mocha ๋ฐ proxyquire๋ก ์์ฑ๋ ํ ์คํธ๋ฅผ ๋ฆฌํฉํฐ๋งํ๊ธฐ ์ํด ์ฌ๊ธฐ์์ ์ฌ๋ฌ ๊ฐ์ง ๋ฐฉ๋ฒ์ผ๋ก ์ด๋ ค์์ ๊ฒช์๊ณ ๊ฒฐ๊ตญ ๋ค๋ฅธ ๋ชจ์์ ๋ํด ํ ์คํธ๋ฅผ ๋ค๋ฅธ ํ์ผ๋ก ๋ถ๋ฆฌํ์ต๋๋ค.
@gcox ๋ชจ๋์ ์ต์์ ์์ค์์ ๋ชจ์(๊ทธ๋ฆฌ๊ณ ์ดํ์ moduleA ์๊ตฌ)๋ฅผ ์๋ํ ๋ค์ ๋ค๋ฅธ ๋์์ด ํ์ํ ๊ฐ ํ ์คํธ์ ๋ํด ๋ชจ์ ๊ตฌํ์ ๋ณ๊ฒฝํด ๋ณด์ จ์ต๋๊น? ์ด๋ฅผ ์ํด mockImplementation ์ ์ฌ์ฉํ ์ ์์ต๋๋ค. ์ด๊ฒ์ด ์ฐ๋ฆฌ๊ฐ ํ ์คํธ ์ค์ํธ์์ ์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ๋ฐฉ๋ฒ์ ๋๋ค.
@antgonzales ๋ชจ๋ ๊ฐ์ ธ์ค๊ธฐ๊ฐ ๋ชจ๋์ ๋งจ ์๋ก
@jkomusin ํ์คํ. ๊ทธ๊ฒ์ OP๊ฐ ์๊ตฌํ ๊ฒ์ด ์๋๋๋ค, IMO. ๋๋ ๊ทธ๋ค์ด ํนํ " require('whatever')
๊ฐ ๋์ผํ ๊ฐ์ฒด๊ฐ ์๋ ์ฌ๋ฌ ์ธ์ ํ
์คํธ์์ ๋ค๋ฅธ ๋ชจ์๋ฅผ ๋ฐํํ๋๋ก ๊ฐ์ ํ๋ ค๋ฉด ์ด๋ป๊ฒ ํด์ผ ํฉ๋๊น?"๋ผ๊ณ ๋ฌป๊ณ ์๋ค๊ณ ์๊ฐํฉ๋๋ค.
ํ ์คํธ ๊ฐ์ ๋ชจ์ ๋ฐํ ๊ฐ์ ๋ณ๊ฒฝํ๋ ค๋ฉด ๋ค์๊ณผ ๊ฐ์ด ํ ์ ์์ต๋๋ค.
jest.mock('whatever');
// Get the mock function
const whatever = require('whatever');
test('test 1', () => {
whatever.mockImplementation(() => 'hello');
});
test('test 2', () => {
whatever.mockImplementation(() => 'world');
});
@gcox ๋ต๋ณ์ ์ ์๊ฒ ํจ๊ณผ๊ฐ ์์์ง๋ง @SimenB ๋ ํจ๊ณผ๊ฐ
@rafaeleyng ํ์ง๋ง ๋ชจ๋์์ ๋ด๋ณด๋ด๋ ๊ฒ์ด ํจ์๊ฐ ์๋ ๊ฒฝ์ฐ @SimenB ๊ฐ ์๋ํ์ง ์์ต๋๋ค ...
@gcox ์์ ์๋ ์ง๋ ๋ช ์๊ฐ ๋์ ๋ฌธ์์์ ๊ฒ์ํ ๋๋ถ๋ถ์ ์ ๋ณด๊ฐ ํฌํจ๋์ด ์์ต๋๋ค. ์ด์จ๋ ํ์ฌ๋ก์๋ ๋งค์ฐ ๋๋ฌธ ๊ณต์ ๋ฌธ์์ ํฌํจ๋์ด์ผ ํ๋ค๊ณ ์ ์ํฉ๋๋ค.
@schumand ๊ฐ ๋ง์ต๋๋ค. ๊ณต์ ๋ฌธ์๋ฅผ ๋ ๋ช ํํ๊ณ ์ ๋ช ํ๊ฒ ๋ง๋์ญ์์ค.
PR์ ํญ์ ๋ฌธ์ ๊ฐ์ ์ ํ์ํฉ๋๋ค ๐
๋ชจ๋ ์์ ๊ธฐ๋ฐ
https://github.com/facebook/jest/issues/2582#issuecomment -378677440 โค๏ธ
ํค์ผ, ์ฐ๊ฒฐ๋ ๋ฌธ์ ๋ฅผ ํตํด ์ด๊ฒ์ ์ฐพ์๊ณ ์์๋์ต๋๋ค.
jest.mock('child_process')
const childProcess = require('child_process')
describe('foo', () => {
test('bar', () => {
childProcess.execSync.mockImplentation(jest.fn().mockReturnValueOnce('wibble'))
// code that itself requires child_process
expect(childProcess.execSync.mock.results[0]).toEqual('wibble')
})
test('baz', () => {
childProcess.execSync.mockImplentation(jest.fn().mockReturnValueOnce('wobble'))
// code that itself requires child_process
expect(childProcess.execSync.mock.results[0]).toEqual('wobble')
})
})
ํ์ํ ์ฝ๋์์ ์ฌ๋ฌ ํจ์/๋ฉ์๋๋ฅผ ๋ชจ์ํด์ผ ํ๋ ๊ฒฝ์ฐ ์ ์ญ์ผ๋ก ์ํํ ๋ ํฉํ ๋ฆฌ๋ฅผ ์ฌ์ฉํ๋ ๋์ ๋ณ๋๋ก ์ค์ ํด์ผ ํฉ๋๋ค.
์ ์ฒ๋ผ ๋จ์ผ ๊ธฐ๋ฅ๋ง ์์ผ๋ฉด ์ ์ฒด๋ฅผ ๋จ์ํํ ์ ์์ต๋๋ค.
jest.mock('child_process')
const { execSync } = require('child_process')
describe('foo', () => {
test('bar', () => {
execSync.mockImplentation(jest.fn().mockReturnValueOnce('wibble'))
// code that itself requires child_process
expect(execSync.mock.results[0]).toEqual('wibble')
})
test('baz', () => {
execSync.mockImplentation(jest.fn().mockReturnValueOnce('wobble'))
// code that itself requires child_process
expect(execSync.mock.results[0]).toEqual('wobble')
})
})
json ํ์ผ์ด๋ ๋งคํ๋ ์์์ ๊ฐ์ ๋นํจ์ ์ข ์์ฑ์ ์กฐ๋กฑํ๋ ๊ฒ์ ์ด๋ป์ต๋๊น? ์ด๊ฒ์ ์ฒ๋ฆฌํ๋ ๋ฐฉ๋ฒ์ ๋ํ ๋ฌธ์๋ฅผ ๋ ๋ช ํํ๊ฒ ๋ง๋์ญ์์ค ...
@gcox ๊ทํ์ ์๋ฃจ์
์ ํ
์คํธ ์ค์ธ ๊ฐ์ ธ์จ ๋ชจ๋์ด __mocks__
ํด๋์ ์๋ ๋ชจ์๊ฐ ์์๋ ๋ค๋ฅธ ๋ชจ๋์ ๊ฐ์ ธ์ฌ ๋ ์ฐพ์ ์ ์ผํ ์๋ฃจ์
์
๋๋ค.
์๋ฅผ ๋ค์ด, ํ
์คํธ ํ์ผ ํธ์ถ jest.mock('./ModuleA')
์ ์ค๋ฌผ ํฌ๊ธฐ์ ๋ชจํ์ด์๋, __mocks__/ModuleA.js
. ๊ทธ๋ฌ๋ ModuleA๋ ํ
์คํธ ์ค์ด ์๋๋ฉฐ ModuleA๊ฐ ํ์ํ ModuleB๋ ํ
์คํธ ์ค์ธ ๊ฒ์
๋๋ค. ์๋ฃจ์
์ด ์์ผ๋ฉด ModuleB๋ ๋ชจ์๊ฐ ์๋ ModuleA์ ์ค์ ๊ตฌํ์ ์ป๊ฒ ๋ฉ๋๋ค.
์ด๊ฒ์ ๋๋ด์ ์ ๋ง ์ด์ํ ํ๋์ฒ๋ผ ๋ณด์ ๋๋ค. ๋ชจ๋์์ jest.mock์ ํธ์ถํ ๋ ๋ชจ์ ๋ชจ๋์ ๋ํ ์ข ์์ฑ์ด ์๋ ํ ์คํธ ์ค์ธ ๋ชจ๋ ๋ชจ๋์ด ๋ชจ์๋ฅผ ์ฌ์ฉํ ๊ฒ์ผ๋ก ์์ํฉ๋๋ค. ๊ทธ๋ฐ ์์ผ๋ก ์๋ํ์ง ์๋ ๊ฒ์ด ์ด์ํ๊ฒ ๋ณด์ ๋๊น, ์๋๋ฉด ์์ ํ ์๋ชป ์งํ๋๊ณ ์์ต๋๊น?
@SimenB ๊ทํ์ ์์์ ์กฐ๋กฑ๋ ๋ชจ๋์ด ํ์ํ๊ณ ํ ์คํธ์์ ์คํํ๋ฉด ์๋ํฉ๋๋ค. ์์์ ์ค๋ช ํ ์๋๋ฆฌ์ค๋ ํจ๊ณผ๊ฐ ์์ ๊ฒ์ผ๋ก ์์ํ์ญ๋๊น? ์ ๋ง ๊ณ ๋ง์.
@SimenB ๊ฐ ๋๋ฅผ ์ํด ๋ ๊ฐ๋จํ ์๋ฃจ์ ์ ์ ๊ณตํ์ต๋๋ค. ๊ฐ์ฌ ํด์! ๋ด๊ฐ ๋ค์ํ ๋ฐฉ๋ฒ์ผ๋ก ์๊ฐ์ ๋ณด๋ด๊ธฐ ์ ์ Wish๋ฅผ ๋ ์ผ์ฐ ์ฐพ์ ์ ์์์ต๋๋ค.
์ ๊ฒฝ์ฐ์๋ ์คํ ํ๋ ค๋ ๋ชจ๋์ ๋ํ ์๋ชป๋ ๊ฒฝ๋ก๋ฅผ ์กฐ๋กฑํ๊ณ ๊ฐ์ ธ์์ต๋๋ค. ํ์ผ ๊ฒฝ๋ก์ ๋์๋ฌธ์๊ฐ ๋ค๋ฅด๊ธฐ ๋๋ฌธ์ ํธ์ง์๋ ๊ด์ฐฎ๋ค๊ณ ์๊ฐํ์ง๋ง ์คํจํ์ต๋๋ค.
์๋ค
const { stubMethod } = require("./path/to/File");
jest.mock("./path/to/File");
๋ค์์ผ๋ก ๋ณ๊ฒฝ๋จ( File
๋ฅผ file
):
const { stubMethod } = require("./path/to/file");
jest.mock("./path/to/file");
์ด๊ฒ์ด ๋ค๋ฅธ ์ฌ๋์ ๋๊ธฐ๋ฅผ ๋ฐ๋๋๋ค.
Jasmine spyOn()
๋ _inside_ ํ
์คํธ์์ ๊ทธ๋ฐ ๋ฌธ์ ๊ฐ ์์ต๋๋ค. Jest๋ ๊ธฐ๋ณธ์ ์ผ๋ก ์ฌ์ค๋ฏผ์ ์ฌ์ฉํ๋ค๊ณ ๊ฐ์ ํฉ๋๊น? ํ
์คํธ ๋ด๋ถ์์ ์๋ํ์ง ์๋ ์ด์ ๋ ๋ฌด์์
๋๊น?
์ฌ์ค๋ฏผ ์:
spyOn(require('moduleB'),ย 'functionA').and.callFake(()ย =>ย true);
๋ชจ์ ๋ชจ๋๊ณผ ๊ด๋ จํ์ฌ ๋ด๊ฐ ์ ์ดํดํ์ง ๋ชปํ๋ ๊ฒ์ ํญ์ ํ
์คํธ ๊ธฐ๋ฅ์์ ์ฃผ๋ก ๋ชจ๋์ ์ฌ์ฉํ๋ ค๋ ๊ฒ์ฒ๋ผ ์ค๋ช
๋๋ค๋ ๊ฒ์
๋๋ค. ์๋ฅผ ๋ค์ด ๋ฌธ์์์ doMock
ํจ์์ ๋ํ ์์ ์ฝ๋๋ฅผ ๋ณด๋ฉด ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
test('moduleName 2', () => {
jest.doMock('../moduleName', () => {
return {
__esModule: true,
default: 'default2',
foo: 'foo2',
};
});
return import('../moduleName').then(moduleName => {
expect(moduleName.default).toEqual('default2');
expect(moduleName.foo).toEqual('foo2');
});
});
์ด ์์์๋ ํ
์คํธ ํจ์ ๋ด์์๋ง ์๋ก ์กฐ๋กฑ๋ "moduleName"
๋ฒ์ ์ ์ก์ธ์คํ ์ ์์ต๋๋ค. ๋์๊ฒ๋ "๋น ํ
์คํธ" ์ฝ๋๊ฐ ๋ชจ๋์ ๋ชจ์ ๋ฒ์ ์๋ ์ก์ธ์คํ ์ ์๋ค๋ ๊ฒ์ด ํจ์ฌ ๋ ์ค์ํฉ๋๋ค. ์๋ฅผ ๋ค์ด, "moduleName"
๊ฐ์ ธ์จ ํ
์คํธ ๋ด์์ ์ฌ์ฉ ์ค์ธ ํด๋์ค๋ ์ฌ์ ํ ์กฐ๋กฑ๋ ๋ฒ์ ์ด ์๋ ์๋ ๋ฒ์ ์ ์ฌ์ฉํ๊ณ ์์ต๋๋ค.
๊ด๋ จ์ด์๋ ๊ฒ ๊ฐ์ต๋๋ค : https://github.com/facebook/jest/issues/3236
ํ - ๊ธฐ๋ณธ ๊ฐ์ ๋ด๋ณด๋ด๋ ๋ชจ๋์ด ์๋ ๊ฒฝ์ฐ, ์:
```auth.js
๋ด๋ณด๋ด๊ธฐ const isUserAdmin = getSetting('๊ด๋ฆฌ์');
And you want to use a mock value instead, in the test, then a simple require and assignment seems to do the trick:
```deleteUser.js
const auth = require('../auth');
describe('deleteUser', () => {
it('can delete if admin', () => {
auth.isUserAdmin = true;
// call method that depends on isUserAdmin value
// and assert on the result
});
});
๋ฐ๋ผ์ ๊ธฐ๋ณธ์ ์ผ๋ก ์ฝ๋์์ ๊ฐ์ ์ ์ผ๋ก ์ฌ์ฉ๋๋ ๊ฐ์ฒด๋ฅผ ๋ชจ์ํ๋ ค๋ ๊ฒฝ์ฐ jest.doMock()
ํจ์๋ฅผ ํ
์คํธํ๋ฉด ์๋ํ์ง ์์ต๋๋ค.
import myModuleToTest from './myModuleTotest'
describe('Given my module', () => {
it('property1 will work as expect', () => {
// Testing parts of the module that don't need to be mocked
})
it('property2 will work as expected', () => {
jest.doMock('./myOtherModule', () => {
return {
__esModule: true,
default: 'default2',
foo: 'foo2',
};
});
import('./myOtherModule').then(myOtherModule => {
// I'm not interested on the mocked module myOtherModule but on the module that makes use of it
myModuleToTest.doSomethingToSomeProperty(); // At this point myOtherModule's original module and not its mocked version will be used by myModuleToTest
expect(myModuleToTest.someProperty).toBe('thisWillFail'); // The test won't pass because the mocked version wasn't used
});
});
});
Jest 26 ํ์ฌ ๊ฐ์ ์ ์ผ๋ก ์ฌ์ฉ๋๋ Object
๋ฅผ ๋ด๋ณด๋ด๋ ๋ชจ๋์ ๋ ๋ฒ ์ด์ ์กฐ๋กฑํ ์ ์๋ ๋ฐฉ๋ฒ์ด ์์ต๋๋ค( mockFn.mockImplementation(fn)
๊ฐ ์๊ธฐ ๋๋ฌธ์ Function
์ด์ธ์ ๋ค๋ฅธ ๊ฒ์ ์กฐ๋กฑํ๋ ๊ฒ์ ์๋ฏธํฉ๋๋ค mockFn.mockImplementation(fn)
์กฐ๋กฑ Objects
). ์ด๊ฒ ๋ง๋์ ์๋๋ฉด ์ ๊ฐ ๋์น๊ณ ์๋ ๋ถ๋ถ์ด ์๋์? ์ ์ผํ ์๋ฃจ์
์ ๋์ผํ ๋ชจ๋์ ํ
์คํธํ๊ธฐ ์ํด ๋ ์ด์์ ํ
์คํธ ํ์ผ์ ๊ฐ๋ ๊ฒ์
๋๋ค.
๋ชจ์ ๊ฐ์ฒด๋ฅผ ๊ฐ์ ธ์จ ํ์ myModuleToTest๋ฅผ ๊ฐ์ ธ์์ผ ํฉ๋๋ค.
์กฐ๋กฑ์ด ์๋ฏธ๊ฐ ์๊ธฐ ์ ์. ๋ฐ๋ผ์ import ....๋ฅผ ์ฌ์ฉํ์ง ๋ง์ญ์์ค.
์ด์จ๋ ํธ์ด์คํธ๋๊ธฐ ๋๋ฌธ์ ์ฝ๋ฐฑ ๋ด๋ถ.
2020๋
7์ 7์ผ ํ์์ผ ์คํ 10:24 Antonio Redondo [email protected]
์ผ๋ค:
๋ฐ๋ผ์ ๊ธฐ๋ณธ์ ์ผ๋ก ๊ฐ์ ์ ์ผ๋ก ์ฌ์ฉ๋๋ ๊ฐ์ฒด๋ฅผ ์กฐ๋กฑํ๋ ค๋ ๊ฒฝ์ฐ
jest.doMock() ํจ์๋ฅผ ํ ์คํธํ๋ ์ฝ๋๋ ์๋ํ์ง ์์ต๋๋ค.'./myModuleTotest'์์ myModuleToTest ๊ฐ์ ธ์ค๊ธฐ
it('์ผํ ๊ฒ์ ๋๋ค', () => {
jest.doMock('./myOtherModule', () => {
๋ฐํ {
__esModule: ์ฐธ,
๊ธฐ๋ณธ๊ฐ: 'default2',
foo: 'foo2',
};
});return import('../myOtherModule').then(myOtherModule => {
// ๋ชจ์ ๋ชจ๋ myOtherModule์๋ ๊ด์ฌ์ด ์์ง๋ง ์ด๋ฅผ ์ฌ์ฉํ๋ ๋ชจ๋์๋ ๊ด์ฌ์ด ์์ต๋๋ค.
myModuleToTest.doSomethingToSomeProperty(); // ์ด ์์ ์์ ๋ชจ์ โโ๋ฒ์ ์ด ์๋ myOtherModule์ ์๋ ๋ชจ๋์ด myModuleToTest์์ ์ฌ์ฉ๋ฉ๋๋ค.
๊ธฐ๋(myModuleToTest.someProperty).toBe('thisWillFail'); // ๋ชจ์ ๋ฒ์ ์ด ์ฌ์ฉ๋์ง ์์๊ธฐ ๋๋ฌธ์ ํ ์คํธ๊ฐ ํต๊ณผํ์ง ์์ต๋๋ค.
});});Jest 26์์๋ ๊ฐ์ฒด๋ฅผ ๋ด๋ณด๋ด๋ ๋ชจ๋์ ์กฐ๋กฑํ ์ ์๋ ๋ฐฉ๋ฒ์ด ์์ต๋๋ค(I
๊ฐ์ ์ ์ผ๋ก ์ฌ์ฉ๋๋ ํจ์ ์ด์ธ์ ๋ค๋ฅธ ๊ฒ์ ์๋ฏธํฉ๋๋ค. ์ด๊ฑฐ์ผ?
์ ํํ๊ฑฐ๋ ๋ด๊ฐ ๋ญ๊ฐ๋ฅผ ๋์น๊ณ ์์ต๋๊น? ์ ์ผํ ํด๊ฒฐ์ฑ ์ ๋ ๋ง์
๋์ผํ ๋ชจ๋์ ํ ์คํธํ๊ธฐ ์ํด ํ๋ ์ด์์ ํ ์คํธ ํ์ผ.โ
๋น์ ์ด ๋๊ธ์ ๋ฌ์๊ธฐ ๋๋ฌธ์ ์ด๊ฒ์ ๋ฐ๋ ๊ฒ์ ๋๋ค.
์ด ์ด๋ฉ์ผ์ ์ง์ ๋ต์ฅํ๊ณ GitHub์์ ํ์ธํ์ธ์.
https://github.com/facebook/jest/issues/2582#issuecomment-655110424 ๋๋
๊ตฌ๋ ์ทจ์
https://github.com/notifications/unsubscribe-auth/AAJR3UW6HARW44ZLKAUB7PLR2N77NANCNFSM4C4I7QSQ
.
๊ฐ์ฅ ์ ์ฉํ ๋๊ธ
ํ ์คํธ ๊ฐ์ ๋ชจ์ ๋ฐํ ๊ฐ์ ๋ณ๊ฒฝํ๋ ค๋ฉด ๋ค์๊ณผ ๊ฐ์ด ํ ์ ์์ต๋๋ค.