如何模拟Typeorm连接 [英] How to mock typeorm connection

查看:130
本文介绍了如何模拟Typeorm连接的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在集成测试中,我使用以下代码片段创建连接

In integration tests I am using the following snippets to create connection

import {Connection, createConnection} from 'typeorm';
// @ts-ignore
import options from './../../../ormconfig.js';

export function connectDb() {
  let con: Connection;

  beforeAll(async () => {
    con = await createConnection(options);
  });

  afterAll(async () => {
    await con.close();
  });

}

我正在尝试对使用其方法之一调用 typeorm存储库的类进行单元测试,而没有调用上面的辅助函数 connectDb(),我得到以下错误,该错误当然是预期的.

I am trying to unit test a class which calls typeorm repository in one of its method and without call that helper function connectDb() above I get the following error which is expected of course.

ConnectionNotFoundError:找不到连接默认".

ConnectionNotFoundError: Connection "default" was not found.

我的问题是我该如何模拟连接.我尝试了以下方法,但没有成功

My question is how can I mock connection. I have tried the following without any success

import typeorm, {createConnection} from 'typeorm';
// @ts-ignore
import options from "./../../../ormconfig.js";

const mockedTypeorm = typeorm as jest.Mocked<typeof typeorm>;

jest.mock('typeorm');

 beforeEach(() => {
    //mockedTypeorm.createConnection.mockImplementation(() => createConnection(options)); //Failed
    mockedTypeorm.createConnection = jest.fn().mockImplementation(() => typeorm.Connection);

    MethodRepository.prototype.changeMethod = jest.fn().mockImplementation(() => {
      return true;
    });
  });

运行带有这种模拟的测试会出现此错误

Running tests with that kind of mocking gives this error

TypeError:装饰器不是函数

TypeError: decorator is not a function

注意:如果我在测试中调用connectDb(),则一切正常.但是我不想这样做,因为在运行任何测试之前,将一些数据插入到db中会花费太多时间. 为了简单起见,一些代码已被省略.任何帮助将不胜感激

Note: if I call connectDb() in tests everything works fine. But I don't want to do that since it takes too much time as some data are inserted into db before running any test. Some codes have been omitted for simplicity. Any help will be appreciated

推荐答案

经过大量的研究和实验,我最终得到了这种解决方案.我希望它对遇到同样问题的其他人也有用...

After a bunch of research and experiment I've ended up with this solution. I hope it works for someone else who experienced the same issue...

  • 它不需要任何数据库连接
  • 测试服务层内容,而不是数据库层本身
  • test可以轻松解决我需要测试的所有情况,我只需要为相关的typeorm方法提供正确的输出即可.

这是我要测试的方法

@Injectable()
export class TemplatesService {
  constructor(private readonly templatesRepository: TemplatesRepository) {}

  async list(filter: ListTemplatesReqDTO) {
    const qb = this.templatesRepository.createQueryBuilder("tl");
    const { searchQuery, ...otherFilters } = filter;
    if (filter.languages) {
      qb.where("tl.language IN (:...languages)");
    }
    if (filter.templateTypes) {
      qb.where("tl.templateType IN (:...templateTypes)");
    }
    if (searchQuery) {
      qb.where("tl.name LIKE :searchQuery", { searchQuery: `%${searchQuery}%` });
    }
    if (filter.skip) {
      qb.skip(filter.skip);
    }
    if (filter.take) {
      qb.take(filter.take);
    }
    if (filter.sort) {
      qb.orderBy(filter.sort, filter.order === "ASC" ? "ASC" : "DESC");
    }
    return qb.setParameters(otherFilters).getManyAndCount();
  }

...
}

这是测试:

import { SinonStub, createSandbox, restore, stub } from "sinon";
import * as typeorm from "typeorm";

describe("TemplatesService", () => {
  let service: TemplatesService;
  let repo: TemplatesRepository;

  const sandbox = createSandbox();
  const connectionStub = sandbox.createStubInstance(typeorm.Connection);
  const templatesRepoStub = sandbox.createStubInstance(TemplatesRepository);
  const queryBuilderStub = sandbox.createStubInstance(typeorm.SelectQueryBuilder);
  stub(typeorm, "createConnection").resolves((connectionStub as unknown) as typeorm.Connection);
  connectionStub.getCustomRepository
    .withArgs(TemplatesRepository)
    .returns((templatesRepoStub as unknown) as TemplatesRepository);

  beforeAll(async () => {
    const builder: TestingModuleBuilder = Test.createTestingModule({
      imports: [
        TypeOrmModule.forRoot({
          type: "postgres",
          database: "test",
          entities: [Template],
          synchronize: true,
          dropSchema: true
        })
      ],
      providers: [ApiGuard, TemplatesService, TemplatesRepository],
      controllers: []
    });
    const module = await builder.compile();

    service = module.get<TemplatesService>(TemplatesService);
    repo = module.get<TemplatesRepository>(TemplatesRepository);
  });

  beforeEach(async () => {
    // do something
  });

  afterEach(() => {
    sandbox.restore();
    restore();
  });

  it("Service should be defined", () => {
    expect(service).toBeDefined();
  });


  describe("list", () => {
    let fakeCreateQueryBuilder;

    it("should return records", async () => {
      stub(queryBuilderStub, "skip" as any).returnsThis();
      stub(queryBuilderStub, "take" as any).returnsThis();
      stub(queryBuilderStub, "sort" as any).returnsThis();
      stub(queryBuilderStub, "setParameters" as any).returnsThis();
      stub(queryBuilderStub, "getManyAndCount" as any).resolves([
        templatesRepoMocksListSuccess,
        templatesRepoMocksListSuccess.length
      ]);
      fakeCreateQueryBuilder = stub(repo, "createQueryBuilder" as any).returns(queryBuilderStub);
      const [items, totalCount] = await service.list({});

      expect(fakeCreateQueryBuilder.calledOnce).toBe(true);
      expect(fakeCreateQueryBuilder.calledOnce).toBe(true);
      expect(items.length).toBeGreaterThan(0);
      expect(totalCount).toBeGreaterThan(0);
    });
  });
});

欢呼!

这篇关于如何模拟Typeorm连接的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆