And*_*aro 36 javascript unit-testing mocking jestjs
我想通过扩展默认mock的行为并在执行以下测试时将其恢复为原始实现来更改每个测试基础上的模拟依赖项的实现.
更简单地说,这就是我想要实现的目标:
我正在使用Jest v21
.
以下是典型的Jest测试:
__mocks__/myModule.js
const myMockedModule = jest.genMockFromModule('../myModule');
myMockedModule.a = jest.fn(() => true);
myMockedModule.b = jest.fn(() => true);
export default myMockedModule;
Run Code Online (Sandbox Code Playgroud)
__tests__/myTest.js
import myMockedModule from '../myModule';
// Mock myModule
jest.mock('../myModule');
beforeEach(() => {
jest.clearAllMocks();
});
describe('MyTest', () => {
it('should test with default mock', () => {
myMockedModule.a(); // === true
myMockedModule.b(); // === true
});
it('should override myMockedModule.b mock result (and leave the other methods untouched)', () => {
// Extend change mock
myMockedModule.a(); // === true
myMockedModule.b(); // === 'overridden'
// Restore mock to original implementation with no side effects
});
it('should revert back to default myMockedModule mock', () => {
myMockedModule.a(); // === true
myMockedModule.b(); // === true
});
});
Run Code Online (Sandbox Code Playgroud)
我尝试了一些策略,但我找不到任何可以定义令人满意的解决方案.
利弊
缺点
b
更多次,它将会中断b
没有调用之前它不会恢复到原始实现(在下一个测试中泄漏)码:
it('should override myModule.b mock result (and leave the other methods untouched)', () => {
myMockedModule.b.mockImplementationOnce(() => 'overridden');
myModule.a(); // === true
myModule.b(); // === 'overridden'
});
Run Code Online (Sandbox Code Playgroud)
利弊
缺点
码:
it('should override myModule.b mock result (and leave the other methods untouched)', () => {
jest.doMock('../myModule', () => {
return {
a: jest.fn(() => true,
b: jest.fn(() => 'overridden',
}
});
myModule.a(); // === true
myModule.b(); // === 'overridden'
});
Run Code Online (Sandbox Code Playgroud)
利弊
缺点
码:
__mocks__/myModule.js
const myMockedModule = jest.genMockFromModule('../myModule');
let a = true;
let b = true;
myMockedModule.a = jest.fn(() => a);
myMockedModule.b = jest.fn(() => b);
myMockedModule.__setA = (value) => { a = value };
myMockedModule.__setB = (value) => { b = value };
myMockedModule.__reset = () => {
a = true;
b = true;
};
export default myMockedModule;
Run Code Online (Sandbox Code Playgroud)
__tests__/myTest.js
it('should override myModule.b mock result (and leave the other methods untouched)', () => {
myModule.__setB('overridden');
myModule.a(); // === true
myModule.b(); // === 'overridden'
myModule.__reset();
});
Run Code Online (Sandbox Code Playgroud)
缺点
mockImplementation
到原始的模拟返回值,因此影响以下测试码:
beforeEach(() => {
jest.clearAllMocks();
jest.restoreAllMocks();
});
// Mock myModule
jest.mock('../myModule');
it('should override myModule.b mock result (and leave the other methods untouched)', () => {
const spy = jest.spyOn(myMockedModule, 'b').mockImplementation(() => 'overridden');
myMockedModule.a(); // === true
myMockedModule.b(); // === 'overridden'
// How to get back to original mocked value?
});
Run Code Online (Sandbox Code Playgroud)
提前感谢您的任何意见/建议!
use*_*118 20
编写测试的一个很好的模式是创建一个设置工厂函数,它返回测试当前模块所需的数据.
下面是您的第二个示例后面的一些示例代码,但允许以可重用的方式提供默认值和覆盖值.
const spyReturns = returnValue => jest.fn(() => returnValue);
describe("scenario", () => {
const setup = (mockOverrides) => {
const mockedFunctions = {
a: spyReturns(true),
b: spyReturns(true),
...mockOverrides
}
return {
mockedModule: jest.doMock('../myModule', () => mockedFunctions)
}
}
it("should return true for module a", () => {
const { mockedModule } = setup();
expect(mockedModule.a()).toEqual(true)
});
it("should return override for module a", () => {
const EXPECTED_VALUE = "override"
const { mockedModule } = setup({ a: spyReturns(EXPECTED_VALUE)});
expect(mockedModule.a()).toEqual(EXPECTED_VALUE)
});
});
Run Code Online (Sandbox Code Playgroud)
A J*_*lay 12
使用mockFn.mockImplementation(fn)。
将默认实现放入beforeEach
。每次测试前,模拟将重置为此。
要覆盖,请mockImplementation
在测试中使用。
这将覆盖测试中任何/所有调用的模拟行为,并且beforeEach
在下一次测试之前将被实现覆盖。
例如:
import { funcToMock } from './somewhere';
jest.mock('./somewhere');
beforeEach(() => {
funcToMock.mockImplementation(() => { /* default implementation */ });
});
test('case that needs a different implementation of funcToMock', () => {
funcToMock.mockImplementation(() => { /* implementation specific to this test */ });
// ...
});
Run Code Online (Sandbox Code Playgroud)
晚会晚了一点,但是如果有人对此有疑问。
我们使用TypeScript,ES6和babel进行本机开发。
我们通常在根__mocks__
目录中模拟外部NPM模块。
我想覆盖aws-amplify的Auth类中模块的特定功能以进行特定测试。
import { Auth } from 'aws-amplify';
import GetJwtToken from './GetJwtToken';
...
it('When idToken should return "123"', async () => {
const spy = jest.spyOn(Auth, 'currentSession').mockImplementation(() => ({
getIdToken: () => ({
getJwtToken: () => '123',
}),
}));
const result = await GetJwtToken();
expect(result).toBe('123');
spy.mockRestore();
});
Run Code Online (Sandbox Code Playgroud)
要点:https : //gist.github.com/thomashagstrom/e5bffe6c3e3acec592201b6892226af2
教程:https: //medium.com/p/b4ac52a005d#19c5
当模拟单个方法时(当需要保持类/模块实现的其余部分完好无损时),我发现以下方法有助于重置单个测试中的任何实现调整。
我发现这种方法是最简洁的方法,不需要jest.mock
在文件开头等处添加任何内容。您只需要下面看到的代码来模拟MyClass.methodName
。另一个优点是,默认情况下spyOn
保留原始方法实现,但也保存所有统计信息(调用、参数、结果等)以进行测试,并且在某些情况下必须保留默认实现。因此,您可以灵活地保留默认实现或通过简单添加来更改它,.mockImplementation
如下面的代码中所述。
代码采用 Typescript 编写,注释突出显示了 JS 的差异(准确地说,差异在一行中)。使用 Jest 26.6 进行测试。
describe('test set', () => {
let mockedFn: jest.SpyInstance<void>; // void is the return value of the mocked function, change as necessary
// For plain JS use just: let mockedFn;
beforeEach(() => {
mockedFn = jest.spyOn(MyClass.prototype, 'methodName');
// Use the following instead if you need not to just spy but also to replace the default method implementation:
// mockedFn = jest.spyOn(MyClass.prototype, 'methodName').mockImplementation(() => {/*custom implementation*/});
});
afterEach(() => {
// Reset to the original method implementation (non-mocked) and clear all the mock data
mockedFn.mockRestore();
});
it('does first thing', () => {
/* Test with the default mock implementation */
});
it('does second thing', () => {
mockedFn.mockImplementation(() => {/*custom implementation just for this test*/});
/* Test utilising this custom mock implementation. It is reset after the test. */
});
it('does third thing', () => {
/* Another test with the default mock implementation */
});
});
Run Code Online (Sandbox Code Playgroud)