如何使用 jest 在打字稿中模拟 mongodb 经理
How to mock mongodb manager in typescript using jest
如何 return 一个 mongodb.connection.db() 类型的值并模拟它的集合?
我创建了一个 mongoClient 类型的连接并使用了它的 db() 函数。如果一切正常,我输入这个的集合信息,但我无法编写测试,因为我无法模拟它。
dbManager.ts
import { MongoClient } from 'mongodb';
class DBManager {
private connection?: MongoClient;
private mongoUrl = null;
constructor(url: string) {
this.mongoUrl = url;
}
get db() {
return this.connection!.db();
}
async start() {
if (!this.connection) {
this.connection = await MongoClient.connect(this.mongoUrl);
}
}
}
export default DBManager;
index.ts
const dbManager = new DBManager(url);
await dbManager.start();
const db = dbManager.db;
if (db) {
const collection = db.collection(collectionName);
}
index.spec.ts
const dbManager = new DBManager( 'mongoUrl');
jest.spyOn(dbManager, 'start').mockResolvedValue();
jest.spyOn(dbManager, 'db', 'get').mockImplementation();
mock不成功的原因是你在测试用例中新建了一个DBManager
实例,而jest.spyOn()
只对这个实例的方法添加了spy。在测试代码中是 DBManager
的另一个实例,仍然调用其原始的 unspy 方法。
您可以将间谍添加到 DBManager.prototype.start()
和 DBManager.prototype.get()
方法。
此外,不要忘记在 afterEach
钩子中将模拟恢复到它们的原始值。保证测试用例的mock对象不会影响其他测试用例。
例如
DBManager.ts
:
import { MongoClient } from 'mongodb';
class DBManager {
private connection?: MongoClient;
private mongoUrl: string = '';
constructor(url: string) {
this.mongoUrl = url;
}
get db() {
return this.connection!.db();
}
async start() {
if (!this.connection) {
this.connection = await MongoClient.connect(this.mongoUrl);
}
}
}
export default DBManager;
index.ts
:
import DBManager from './dbManager';
export async function main() {
const url = 'mongodb://localhost:27017';
const collectionName = 'user';
const dbManager = new DBManager(url);
await dbManager.start();
const db = dbManager.db;
if (db) {
const collection = db.collection(collectionName);
}
}
index.test.ts
:
import { main } from './';
import DBManager from './dbManager';
import { Db } from 'mongodb';
describe('69011729', () => {
afterEach(() => {
jest.restoreAllMocks();
});
test('should pass', async () => {
const mDB = ({
collection: jest.fn(),
} as unknown) as Db;
jest.spyOn(DBManager.prototype, 'start').mockResolvedValue();
jest.spyOn(DBManager.prototype, 'db', 'get').mockReturnValueOnce(mDB);
await main();
expect(DBManager.prototype.start).toBeCalledTimes(1);
expect(mDB.collection).toBeCalledWith('user');
});
test('should restore original methods', () => {
expect(jest.isMockFunction(DBManager.prototype.start)).toBeFalsy();
});
});
测试结果:
PASS examples/69011729/index.test.ts (10.734 s)
69011729
✓ should pass (4 ms)
✓ should restore original methods
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 11.516 s
Ran all test suites related to changed files.
如何 return 一个 mongodb.connection.db() 类型的值并模拟它的集合? 我创建了一个 mongoClient 类型的连接并使用了它的 db() 函数。如果一切正常,我输入这个的集合信息,但我无法编写测试,因为我无法模拟它。
dbManager.ts
import { MongoClient } from 'mongodb';
class DBManager {
private connection?: MongoClient;
private mongoUrl = null;
constructor(url: string) {
this.mongoUrl = url;
}
get db() {
return this.connection!.db();
}
async start() {
if (!this.connection) {
this.connection = await MongoClient.connect(this.mongoUrl);
}
}
}
export default DBManager;
index.ts
const dbManager = new DBManager(url);
await dbManager.start();
const db = dbManager.db;
if (db) {
const collection = db.collection(collectionName);
}
index.spec.ts
const dbManager = new DBManager( 'mongoUrl');
jest.spyOn(dbManager, 'start').mockResolvedValue();
jest.spyOn(dbManager, 'db', 'get').mockImplementation();
mock不成功的原因是你在测试用例中新建了一个DBManager
实例,而jest.spyOn()
只对这个实例的方法添加了spy。在测试代码中是 DBManager
的另一个实例,仍然调用其原始的 unspy 方法。
您可以将间谍添加到 DBManager.prototype.start()
和 DBManager.prototype.get()
方法。
此外,不要忘记在 afterEach
钩子中将模拟恢复到它们的原始值。保证测试用例的mock对象不会影响其他测试用例。
例如
DBManager.ts
:
import { MongoClient } from 'mongodb';
class DBManager {
private connection?: MongoClient;
private mongoUrl: string = '';
constructor(url: string) {
this.mongoUrl = url;
}
get db() {
return this.connection!.db();
}
async start() {
if (!this.connection) {
this.connection = await MongoClient.connect(this.mongoUrl);
}
}
}
export default DBManager;
index.ts
:
import DBManager from './dbManager';
export async function main() {
const url = 'mongodb://localhost:27017';
const collectionName = 'user';
const dbManager = new DBManager(url);
await dbManager.start();
const db = dbManager.db;
if (db) {
const collection = db.collection(collectionName);
}
}
index.test.ts
:
import { main } from './';
import DBManager from './dbManager';
import { Db } from 'mongodb';
describe('69011729', () => {
afterEach(() => {
jest.restoreAllMocks();
});
test('should pass', async () => {
const mDB = ({
collection: jest.fn(),
} as unknown) as Db;
jest.spyOn(DBManager.prototype, 'start').mockResolvedValue();
jest.spyOn(DBManager.prototype, 'db', 'get').mockReturnValueOnce(mDB);
await main();
expect(DBManager.prototype.start).toBeCalledTimes(1);
expect(mDB.collection).toBeCalledWith('user');
});
test('should restore original methods', () => {
expect(jest.isMockFunction(DBManager.prototype.start)).toBeFalsy();
});
});
测试结果:
PASS examples/69011729/index.test.ts (10.734 s)
69011729
✓ should pass (4 ms)
✓ should restore original methods
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 11.516 s
Ran all test suites related to changed files.