Тест метода node.js с использованием knex с sqlite3 никогда не останавливается - PullRequest
0 голосов
/ 01 ноября 2019

Что я хочу сделать

Я пытаюсь протестировать 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",
  }
}

1 Ответ

1 голос
/ 01 ноября 2019

Так как вы используете mocha, кажется, лучше всего использовать after hook Mocha и оттуда звонить destroy. Точно так же вы можете создать Knex в before. Я не могу вспомнить причину, по которой вам нужно было бы позвонить destroy в вашем не тестовом коде.

...