Что я хочу сделать
Я пытаюсь протестировать node.js
функцию, которая использует knex
.
Вместо того, чтобы просто дразнить knex
, я думаю, это интереснона самом деле запустить тест в базе данных в памяти, что делает этот тест не строго унитарным, но для меня это единственный полезный способ проверить класс repository
.
Это также самый популярный ответ здесь: https://stackoverflow.com/a/32749601/1187067
Что я использую в своем тесте
- Упрощенное хранилище книг
bookRepo.js
на основе knex
- Тест
bookRepo.test.js
, вводящийknex
соединение основано на SQLite3
.
Проблема
База данных хорошо инициализирована, тест выполнен успешно, функция afterEach()
успешно запущена, но процесс никогда не заканчивается , что особенно проблематично для конвейеров.
Единственный способ остановить процесс - это вызвать knex.destroy()
в bookRepo.js и bookRepo.test.js, но это не так. можно уничтожить knex, потому что его нельзя будет использовать более одного раза.
Спасибо запомогая!
Код
bookRepo.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
});
});
package.json
…
dependencies": {
"knex": "^0.20.1",
},
"devDependencies": {
"chai": "latest",
"mocha": "^6.2.2",
"sqlite3": "latest",
}
}