14

我一直在成功使用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);
});

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

我也尝试过创建一个自定义 Knex Client,但这也没有奏效。

4

6 回答 6

10

使用玩笑

/__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

于 2019-04-10T02:17:00.150 回答
1

我正在使用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
    })
于 2020-08-25T09:59:03.210 回答
1

我一直在使用内存中的 Sqlite3 数据库进行自动化测试,并取得了巨大的成功。这不是真正的单元测试,但它的运行速度确实比 MySQL 或 PostgreSQL 快得多。我在另一个问题上发布了有关此解决方案的更多详细信息。

于 2015-09-23T21:19:03.713 回答
0

我用 jest 来模拟 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)
于 2018-10-09T10:21:32.347 回答
0

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

例如:

// 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]);
  });
});
于 2021-05-16T15:32:33.087 回答
0

这对我有用,希望对某人有所帮助:

//db.ts
import knex from 'knex';

const db = knex({
  client: 'pg',
  connection: {},
  pool: { min: 0, max: 1 }
});

export default db('someTableName');

//myFunction.ts
//somewhere inside a function
const data = await db
    //   Knex query builders are mutable so when re-using them .clone() is necessary.
    .clone()
    .where({ pk: 'someId', sk: 'someId2' })
    .select('data')
    .orderBy('inserted_at', 'desc')
    .first()

//myFunction.test.ts
describe("myFunction", () => {
  beforeEach(() => {
    jest.spyOn(db, "clone").mockImplementation(() => db);
    jest.spyOn(db, "select");
    jest.spyOn(db, "where");
    jest.spyOn(db, "orderBy");
  });

  afterEach(() => {
    jest.clearAllMocks();
  });

  it("should work as expected", async () => {
    jest.spyOn(db, "first").mockResolvedValueOnce("desiredReturnValue");

    await myFunction();

    expect(db.where).toHaveBeenCalledWith({
      pk: "someId",
      sk: "someId2",
    });
    expect(db.select).toHaveBeenCalledWith("data");
    expect(db.orderBy).toHaveBeenCalledWith("inserted_at", "desc");
    expect(db.first).toHaveBeenCalledTimes(1);
  });
});
于 2022-01-05T18:09:35.477 回答