【问题标题】:How to mock typeorm connection如何模拟 typeorm 连接
【发布时间】:2020-07-03 22:15:43
【问题描述】:

在集成测试中,我使用以下 sn-ps 来创建连接

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 repository 的类进行单元测试,并且没有调用上面的辅助函数 connectDb() 我收到以下错误理所当然。

ConnectionNotFoundError:找不到连接“默认”。

我的问题是如何模拟连接。我尝试了以下没有任何成功

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;
    });
  });

使用这种模拟运行测试会出现此错误

TypeError:装饰器不是函数

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

【问题讨论】:

  • 装饰器是 typeorm Connection 上的方法吗?
  • @Nux 这个问题你解决了吗?如果是这样,你能分享你的解决方案吗?
  • @Orhaan 我还没解决!但是阅读这个问题它可能会给你正确的方向stackoverflow.com/questions/61693597/…

标签: node.js unit-testing jestjs typeorm


【解决方案1】:

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

  • 它不需要任何数据库连接
  • 测试服务层内容,而不是 DB 层本身
  • 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);
    });
  });
});

干杯!

【讨论】:

    猜你喜欢
    • 2021-04-03
    • 2019-11-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-26
    相关资源
    最近更新 更多