在 class 'a' 中调用的来自 class 'b' 的模拟方法
Mock method from class 'b' that is called in class 'a'
我正在尝试测试 class test.controller.ts 中的一个方法,这个方法也恰好调用了另一个正在单独测试的 class 的方法,所以我想嘲笑那个电话。
这里有一个示例设置来展示我正在尝试做的事情。
TestController.test.ts
import {TestController} from "../../src/controllers/test.controller";
import {TestService} from "../../src/services/test.service";
describe("Test TestController", () => {
test("exampleController", () => {
jest.mock('../../src/services/test.service');
let testService = new TestService();
let testController = new TestController();
// Mock testService.exampleService so it returns 2.
let result = testController.exampleController();
expect(result).resolves.toBe(2);
});
});
test.controller.ts
import {TestService} from "../services/test.service";
export class TestController {
private testService: TestService;
constructor() {
this.testService = new TestService();
}
public async exampleController() {
return await this.testService.exampleService();
}
}
test.service.ts
export class TestService {
public async exampleService() {
return 1;
}
}
如何模拟方法 'exampleService' 以便从 test.controller.ts 调用方法 'exampleController' 时使用这个模拟版本?
对于模拟函数,您可以使用 sinon 库。可以如下图所示完成:
let testService = new TestService();
sinon.stub(testService, "exampleService").callsFake(function fakeFn() {
return 2;
});
如果您需要指定 return 值并用模拟函数完全替换函数的实现,可以使用 jest.fn
和 mockImplementationOnce
方法来完成模拟函数。
TestController.test.ts
应该看起来像
import {TestController} from "../../src/controllers/test.controller";
import {TestService} from "../../src/services/test.service";
describe("Test TestController", () => {
test("exampleController", () => {
jest.mock('../../src/services/test.service');
let testService = new TestService();
let testController = new TestController();
// Mock testService.exampleService so it returns 2.
testService.exampleService = jest.fn().mockImplementationOnce(() => Promise.resolve(2));
let result = testController.exampleController();
expect(result).resolves.toBe(2);
});
});
您需要模拟 TestController
class 的 testService
字段。
但是使用您当前的代码,这是不可能的,因为它是私有成员。
这就是首选使用依赖注入的原因,因此我们需要将您的构造函数更改为此,
constructor(testService: TestService) {
this.testService = testService;
}
我们现在传递 TestService
的对象,而不是在构造函数中实例化 testService,以便于模拟。
然后你可以这样测试,
import {TestController} from "./controller";
import {TestService} from "./service";
jest.mock('./service.ts')
describe("Test TestController", () => {
test("exampleController", async () => {
let testService = new TestService();
jest.spyOn(testService, 'exampleService').mockResolvedValue(2)
let testController = new TestController(testService);
let result = await testController.exampleController();
expect(result).toBe(2);
});
});
这里你创建一个TestService
的对象。
然后你在 testService
对象的 exampleService
方法上创建一个间谍,并将其解析值模拟为 return 2.
然后你把它传给TestController的构造器,这个叫依赖注入,测试起来更方便。
然后你继续按照你的期望断言。
我正在尝试测试 class test.controller.ts 中的一个方法,这个方法也恰好调用了另一个正在单独测试的 class 的方法,所以我想嘲笑那个电话。
这里有一个示例设置来展示我正在尝试做的事情。
TestController.test.ts
import {TestController} from "../../src/controllers/test.controller";
import {TestService} from "../../src/services/test.service";
describe("Test TestController", () => {
test("exampleController", () => {
jest.mock('../../src/services/test.service');
let testService = new TestService();
let testController = new TestController();
// Mock testService.exampleService so it returns 2.
let result = testController.exampleController();
expect(result).resolves.toBe(2);
});
});
test.controller.ts
import {TestService} from "../services/test.service";
export class TestController {
private testService: TestService;
constructor() {
this.testService = new TestService();
}
public async exampleController() {
return await this.testService.exampleService();
}
}
test.service.ts
export class TestService {
public async exampleService() {
return 1;
}
}
如何模拟方法 'exampleService' 以便从 test.controller.ts 调用方法 'exampleController' 时使用这个模拟版本?
对于模拟函数,您可以使用 sinon 库。可以如下图所示完成:
let testService = new TestService();
sinon.stub(testService, "exampleService").callsFake(function fakeFn() {
return 2;
});
如果您需要指定 return 值并用模拟函数完全替换函数的实现,可以使用 jest.fn
和 mockImplementationOnce
方法来完成模拟函数。
TestController.test.ts
应该看起来像
import {TestController} from "../../src/controllers/test.controller";
import {TestService} from "../../src/services/test.service";
describe("Test TestController", () => {
test("exampleController", () => {
jest.mock('../../src/services/test.service');
let testService = new TestService();
let testController = new TestController();
// Mock testService.exampleService so it returns 2.
testService.exampleService = jest.fn().mockImplementationOnce(() => Promise.resolve(2));
let result = testController.exampleController();
expect(result).resolves.toBe(2);
});
});
您需要模拟 TestController
class 的 testService
字段。
但是使用您当前的代码,这是不可能的,因为它是私有成员。
这就是首选使用依赖注入的原因,因此我们需要将您的构造函数更改为此,
constructor(testService: TestService) {
this.testService = testService;
}
我们现在传递 TestService
的对象,而不是在构造函数中实例化 testService,以便于模拟。
然后你可以这样测试,
import {TestController} from "./controller";
import {TestService} from "./service";
jest.mock('./service.ts')
describe("Test TestController", () => {
test("exampleController", async () => {
let testService = new TestService();
jest.spyOn(testService, 'exampleService').mockResolvedValue(2)
let testController = new TestController(testService);
let result = await testController.exampleController();
expect(result).toBe(2);
});
});
这里你创建一个TestService
的对象。
然后你在 testService
对象的 exampleService
方法上创建一个间谍,并将其解析值模拟为 return 2.
然后你把它传给TestController的构造器,这个叫依赖注入,测试起来更方便。
然后你继续按照你的期望断言。