我有一个类Qux
,它是从类Baa
继承的,我想在测试Qux
时模拟Baa
。如果我不尝试监视模拟BaaMock
,则原则上可行。
如果我想监视模拟的类,doc说我应该使用jest.fn()而不是类。但是,这似乎无法正常工作:继承类Qux
的某些方法丢失了。
一些示例代码(也可以从https://github.com/stefaneidelloth/testDemoES6Jest获得):
超级类Baa(/src/baa.js):
import Foo from './foo.js';
export default class Baa extends Foo {
constructor(name){
super(name);
}
baaMethod(){
return 'baaMethod';
}
overridableMethod() {
return 'baa';
}
}
继承类Qux(/src/qux.js):
import Baa from './baa.js';
export default class Qux extends Baa {
constructor(name){
super(name);
}
quxMethod(){
return 'quxMethod';
}
overridableMethod() {
return 'qux';
}
}
A。测试继承类Qux的可能性(/test/qux.test.js):
jest.mock('./../src/baa.js', () => {
return class BaaMock {
constructor(name){
this.name = name;
}
baaMethod(){
return 'baaMockedMethod';
}
}
});
import Qux from './../src/qux.js';
describe('Qux', function(){
var sut;
beforeEach(function(){
sut = new Qux('qux');
});
it('quxMethod', function(){
expect(sut.quxMethod()).toEqual('quxMethod');
});
it('baaMethod', function(){
expect(sut.baaMethod()).toEqual('baaMockedMethod');
});
it('overridableMethod', function(){
expect(sut.overridableMethod()).toEqual('qux');
});
});
B。。为了能够监视模拟的类,我尝试用模拟函数替换该类(另请参见https://jestjs.io/docs/en/es6-class-mocks):
import Baa from './../src/baa.js';
jest.mock('./../src/baa.js',
function(){
return jest.fn().mockImplementation(
function(name){
return {
name:name,
baaMethod: () =>{ return 'baaMockedMethod';}
};
}
);
}
);
import Qux from './../src/qux.js';
describe('Qux', function(){
var sut;
beforeEach(function(){
//Baa.mockClear();
sut = new Qux('qux');
//expect(Baa).toHaveBeenCalledTimes(1);
});
it('quxMethod', function(){
expect(sut.quxMethod()).toEqual('quxMethod');
});
it('baaMethod', function(){
expect(sut.baaMethod()).toEqual('baaMockedMethod');
});
it('overridableMethod', function(){
expect(sut.overridableMethod()).toEqual('qux');
});
});
结果,测试失败并出现以下错误:
FAIL test/qux.test.js
Qux
× quxMethod (7ms)
√ baaMethod (4ms)
× overridableMethod (2ms)
● Qux › quxMethod
TypeError: sut.quxMethod is not a function
28 |
29 | it('quxMethod', function(){
> 30 | expect(sut.quxMethod()).toEqual('quxMethod');
| ^
31 | });
32 |
33 | it('baaMethod', function(){
at Object.quxMethod (test/qux.test.js:30:14)
● Qux › overridableMethod
TypeError: sut.overridableMethod is not a function
36 |
37 | it('overridableMethod', function(){
> 38 | expect(sut.overridableMethod()).toEqual('qux');
| ^
39 | });
40 |
41 | });
at Object.overridableMethod (test/qux.test.js:38:14)
我希望sut
的实例Qux
仍包含类Qux定义的方法quxMethod
和overridableMethod
。
=> 这是个玩笑吗?
=> 如果没有,为什么我需要在Baa的模拟中实现Qux的所有方法!???
=> 我需要如何适应示例代码 B 才能成功模拟Baa类,以便Qux仍然能够继承它?
答案 0 :(得分:1)
Modify this
将覆盖原来的方法。对于您的示例,如果我想模拟 overridableMethod
,我会修改 overridableMethod
的 this
:
jest.mock('../../src/baa.js',
function(){
return jest.fn().mockImplementation(
function(name){
this.name=name;
this.baaMethod = ()=>{
return 'baaMockedMethod';
};
// mock overridable method
this.overridableMethod = ()=>{
return 'mock'
}
return this;
}
);
}
);
这使得测试错误:
● Qux › overridableMethod
expect(received).toEqual(exptected) // deep equality
Expected: "qux"
Received: "mock"
51 |
52 | it("overridableMethod", function () {
> expect(sut.overridableMethod()).toEqual("qux");
| ^
54 | });
55 | });
56 |
at Object.<anonymous> (tests/unit/qux.spec.js:53:37)
你可以使用类模拟来解决这个问题:
const mockConstructor = jest.fn().mockImplementation(function(name){this.name = name})
const mockOverridableMethod = jest.fn(() => 'mock')
const mockBaaMethod = jest.fn(() => 'baaMockedMethod')
jest.mock("../../src/baa.js", () => {
return class BaaMock {
constructor(name) {
return (mockConstructor.bind(this))(name)
}
overridableMethod() {
return mockOverridableMethod()
}
baaMethod() {
return mockBaaMethod()
}
};
});
import Qux from "../../src/qux.js";
describe("Qux", function () {
var sut;
beforeEach(function () {
mockConstructor.mockClear()
sut = new Qux("qux");
expect(mockConstructor).toHaveBeenCalledTimes(1); // use mockConstructor check if have been called
});
it("quxMethod", function () {
expect(sut.quxMethod()).toEqual("quxMethod");
});
it("baaMethod", function () {
expect(sut.baaMethod()).toEqual("baaMockedMethod");
});
it("overridableMethod", function () {
expect(sut.overridableMethod()).toEqual("qux");
});
});
对包括构造函数在内的每个函数都使用 jest.fn()
让我们可以窥探这些函数。
答案 1 :(得分:0)
我相信您不应该那样做。我没有几个避免这种方法的强烈理由:
总结以上所有内容,我建议您不惜一切代价模拟超类。
答案 2 :(得分:0)
在mockImplementation
的功能内,可以使用上下文this
。以下代码有效:
import Baa from './../src/baa.js';
jest.mock('./../src/baa.js',
function(){
return jest.fn().mockImplementation(
function(name){
this.name=name;
this.baaMethod = ()=>{
return 'baaMockedMethod';
};
return this;
}
);
}
);
import Qux from './../src/qux.js';
describe('Qux', function(){
var sut;
beforeEach(function(){
Baa.mockClear();
sut = new Qux('qux');
expect(Baa).toHaveBeenCalledTimes(1);
});
it('quxMethod', function(){
expect(sut.quxMethod()).toEqual('quxMethod');
});
it('baaMethod', function(){
expect(sut.baaMethod()).toEqual('baaMockedMethod');
});
it('overridableMethod', function(){
expect(sut.overridableMethod()).toEqual('qux');
});
});