如何针对Knex进行单元测试时,如何模拟假数据库?

时间:2015-01-27 07:09:42

标签: javascript node.js unit-testing knex.js proxyquire

我一直在成功使用Knex连接到后端数据库。但我希望能够对我的代码进行单元测试。有没有办法模拟数据库连接?

我尝试过使用proxyquire,但似乎无法让它发挥作用。

问题似乎与Knex的初始化方式有关。

var knex = require('knex')({
  client: 'mysql',
  connection: {}
});

我设置knex在我的单元测试中被嘲笑。

myService = proxyquire('../app/myService', {
        'knex': knexProxy
});

我的服务包括knex。

var knex = require('knex').knex,

当我的服务运行查询时,它会失败。

var sql = knex("table_name");
sql.insert(rowToInsert, "auto_increment_id");
sql.then(function (insertId) {
    resolve();
}, function (err) {
    reject(err);
});

出于某种原因,我似乎无法在尝试连接之前捕获请求。

我也试图创建一个custom Knex Client,但这还没有成功。

5 个答案:

答案 0 :(得分:1)

我一直在使用in-memory Sqlite3 databases进行自动化测试并取得了巨大成功。这不是真正的单元测试,但它的运行速度比MySQL或PostgreSQL快得多。我已发布有关此解决方案的更多详细信息on a different question

答案 1 :(得分:1)

使用jest

在您的应用根目录中创建文件/__mocks__/knex.js

module.exports = () => ({
  select: jest.fn().mockReturnThis(),
  from: jest.fn().mockReturnThis(),
  where: jest.fn().mockReturnThis(),
  first: jest.fn().mockReturnThis(),
  then: jest.fn(function (done) {
    done(null)
  })
})

将所需的返回值传递给done

答案 2 :(得分:0)

我用玩笑来模拟knex,但是我必须定义一个包含我使用的方法的对象。 不是最优雅的解决方案,但是可以正常工作

let knexMock = () => {
    const fn = () => {
        return {
            returning: function() {
                return {
                    insert: jest.fn().mockImplementation(() => [123123])
                }
            },
            insert: jest.fn()
        }
    }
    fn.raw = jest.fn()
    return fn
}

knex.mockImplementation(knexMock)

答案 3 :(得分:0)

我正在使用jest,您可以执行以下操作:

   jest.mock('knex', () => {
        const fn = () => {
            return {
                select: jest.fn().mockReturnThis(),
                from: jest.fn().mockReturnThis(),
                where: jest.fn().mockReturnThis(),
                first: jest.fn().mockReturnThis(),
                insert: jest.fn().mockReturnThis(),
                raw: jest.fn().mockReturnThis(),
                then: jest.fn(function (done) {
                  done(null)
                })
                
            }
        }
        return fn
    })

答案 4 :(得分:0)

我编写了一个名为 knex-mock-client 的小库,它正是这样做的,它允许您使用模拟客户端设置数据库“连接”,该模拟客户端将跟踪您的呼叫并帮助您做出响应。

例如:

// my-cool-controller.ts

import { db } from '../common/db-setup';

export async function addUser(user: User): Promise<{ id }> {
  const [insertId] = await db.insert(user).into('users');

  return { id: insertId };
}
// my-cool-controller.spec.ts
import { expect } from '@jest/globals';
import knex, { Knex } from 'knex';
import { getTracker, MockClient } from 'knex-mock-client';
import faker from 'faker';

jest.mock('../common/db-setup', () => {
  return knex({ client: MockClient });
});

describe('my-cool-controller tests', () => {
  let tracker: Tracker;

  beforeAll(() => {
    tracker = getTracker();
  });

  afterEach(() => {
    tracker.reset();
  });

  it('should add new user', async () => {
    const insertId = faker.datatype.number();
    tracker.on.insert('users').response([insertId]);
    const newUser = { name: 'foo bar', email: 'test@test.com' };
    const data = await addUser(newUser);

    expect(data.id).toEqual(insertId);

    const insertHistory = tracker.history.insert;

    expect(insertHistory).toHaveLength(1);
    expect(insertHistory[0].method).toEqual('insert');
    expect(insertHistory[0].bindings).toEqual([newUser.name, newUser.email]);
  });
});