我想做什么
我正在尝试测试使用knex
的node.js
函数。
不仅仅是嘲笑knex
,我认为在内存数据库中实际运行测试很有趣,这使得这个测试不是严格的单一的,但对我来说,这是测试repository
类的唯一有用方法。
这也是这里投票最多的答案:https://stackoverflow.com/a/32749601/1187067
我在测试中使用了什么
- 基于
knex
的简化图书存储库bookRepo.js
- 测试
bookRepo.test.js
注入基于SQLite3
的knex
连接。
问题
数据库初始化良好,测试成功,afterEach()
函数被很好地调用,但该过程永远不会结束,这对于管道来说尤其成问题。
我发现停止该过程的唯一方法是在bookRepo.js和bookRepo.test.js中调用knex.destroy()
,但不可能销毁knex,因为不可能多次使用它。
感谢您的帮助!
法典
书回购.js
const knex = require('connection'); // dependency not injected in constructor
const TABLE = 'books';
class BookRepo {
constructor() {
this.knex = knex;
}
static getTable() {
return TABLE;
}
async getTitleById(id) {
const book = await this.knex(TABLE)
.select('title')
.where('id', id)
.first();
return book.title;
}
}
module.exports = BookRepo;
bookRepo.test.js
const { assert } = require('chai');
const mock = require('mock-require');
const {
describe,
it,
before,
after,
beforeEach,
afterEach,
} = require('mocha');
const sqliteConf = {
client: 'sqlite3',
connection: {
filename: ':memory:',
},
useNullAsDefault: true,
};
const knex = require('knex')(sqliteConf);
const booksTable = BookRepo.getTable();
const BOOK_1 = {
id: 1,
title: 'Batman',
};
let bookRepo;
describe('getTitleById', () => {
before(() => {
// To use sqlite3 in the tested module, replace knexfile (required by connections)
mock('../knexfile', {
development: sqliteConf,
});
// as knex is not injected in constructor, we need to require BookRepo after having mocked knexfile.
const BookRepo = require('../bookRepo');
bookRepo = new BookRepo();
});
after(() => {
mock.stopAll();
knex.destroy(); // destroys only the connection of the test, not in bookRepo
});
/**
* We initialize the SQLite database before each test (create table and insert)
*/
beforeEach(async () => {
// drop table
await knex.schema.dropTableIfExists(booksTable);
// create table
await knex.schema.createTable(booksTable, (table) => {
table.integer('id');
table.string('title');
});
// Insertion
await knex.transaction((t) => knex(booksTable)
.transacting(t)
.insert(BOOK_1)
.then(t.commit)
.catch(t.rollback))
.catch((e) => {
console.error(e);
throw new Error('failed to insert test data');
});
});
/**
* We drop the SQLite table after each test
*/
afterEach(async () => {
await knex.schema.dropTableIfExists(booksTable); // table well dropped
});
it('returns the title of the given book', async () => {
const bookRepo = new BookRepo();
const expectedTitle = BOOK_1.title;
const retrievedTitle = await bookRepo.getTitleById(BOOK_1.id);
assert.equal(retrievedTitle, expectedTitle); // OK
});
});
包.json
…
dependencies": {
"knex": "^0.20.1",
},
"devDependencies": {
"chai": "latest",
"mocha": "^6.2.2",
"sqlite3": "latest",
}
}
既然你使用的是摩卡,似乎最好使用摩卡的after
钩并从那里调用destroy
。同样,您可以在before
中实例化 Knex。我想不出您需要在非测试代码中调用destroy
的原因。