如何在 beforeEach 中模拟 Knex (Knex)
How to mock Knex in beforeEach (Knex)
我绞尽脑汁想了解如何模拟第三方库。我是 TDD 的新手,因此现在所有的信息对我来说都没有意义。
我想这样测试我的 class:
// 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)
}
首先,Typescript 不允许我这样做Knex.mockImplementation
。其次,我不知道如何告诉 Jest 最后一个链式函数(交易)在不同的测试中应该 return 不同的值。
如何使用 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/Whosebug/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
我绞尽脑汁想了解如何模拟第三方库。我是 TDD 的新手,因此现在所有的信息对我来说都没有意义。
我想这样测试我的 class:
// 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)
}
首先,Typescript 不允许我这样做Knex.mockImplementation
。其次,我不知道如何告诉 Jest 最后一个链式函数(交易)在不同的测试中应该 return 不同的值。
如何使用 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/Whosebug/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