问题描述
我正在努力尝试了解如何嘲笑第三方库。我对TDD完全陌生,因此那里的所有信息现在对我来说都没有意义。
我要以此方式测试我的课程:
// my-class.test.ts
import { MyClass } from './my-class';
describe('Testing my class',() => {
let myClass: MyClass;
beforeEach(() => {
jest.mock('knex',() => jest.fn());
const knex = import('knex').Knex;
const transacting = jest.fn();
const where = jest.fn(() => ({ transacting }));
const from = jest.fn(() => ({ where }));
const withSchema = jest.fn(() => ({ from }));
const select = jest.fn(() => ({ withSchema }));
knex.mockImplementation(() => ({select}));
myClass = new MyClass(knex,???)
});
test(("should return mocked value") => {
// ???
})
});
我基本上想在MyClass
中测试像这样的方法:
// my-class.ts
export class MyClass {
private knex: Knex;
private transaction: Knex.Transaction;
constructor(knex: Knex,transaction: Knex.Transaction) {
this.knex = knex;
this.transaction = transaction;
}
async myMethod(id: string){
return await this.knex
.select('name')
.withSchema('public')
.from('table')
.where({ id })
.transacting(this.transaction)
}
首先,打字稿不允许我做Knex.mockImplementation
。其次,我不知道如何告诉Jest,最后一个链接的函数(正在执行)应该在不同的测试中返回不同的值。
如何用Jest做到这一点?
解决方法
对于您的情况,最好使用依赖项注入将模拟对象传递到MyClass
中。因此,您无需调用jest.mock
来模拟knex
模块。
例如
my-class.ts
:
import Knex from 'knex';
export class MyClass {
private knex: Knex;
private transaction: Knex.Transaction;
constructor(knex: Knex,transaction: Knex.Transaction) {
this.knex = knex;
this.transaction = transaction;
}
async myMethod(id: string) {
return await this.knex
.select('name')
.withSchema('public')
.from('table')
.where({ id })
.transacting(this.transaction);
}
}
my-class.test.ts
:
import { MyClass } from './my-class';
import Knex from 'knex';
describe('63863647',() => {
it('should pass',async () => {
const chainable = ({
transacting: jest.fn().mockResolvedValueOnce({ id: '1',name: 'a' }),} as unknown) as Knex.ChainableInterface;
const mKnex = ({
select: jest.fn().mockReturnThis(),withSchema: jest.fn().mockReturnThis(),from: jest.fn().mockReturnThis(),where: jest.fn().mockReturnValueOnce(chainable),} as unknown) as Knex;
const mTransaction = ({} as unknown) as Knex.Transaction;
const myclass = new MyClass(mKnex,mTransaction);
const actual = await myclass.myMethod('1');
expect(actual).toEqual({ id: '1',name: 'a' });
expect(mKnex.select).toBeCalledWith('name');
expect(mKnex.withSchema).toBeCalledWith('public');
expect(mKnex.from).toBeCalledWith('table');
expect(mKnex.where).toBeCalledWith({ id: '1' });
expect(chainable.transacting).toBeCalledWith(mTransaction);
});
});
具有覆盖率报告的单元测试结果:
PASS src/stackoverflow/63863647/my-class.test.ts
63863647
✓ should pass (7ms)
-------------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
-------------|----------|----------|----------|----------|-------------------|
All files | 100 | 100 | 100 | 100 | |
my-class.ts | 100 | 100 | 100 | 100 | |
-------------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed,1 total
Tests: 1 passed,1 total
Snapshots: 0 total
Time: 4.666s,estimated 13s