服务的 NestJS 单元测试:模拟 getManager 导致“未找到连接“默认””错误
Posted
技术标签:
【中文标题】服务的 NestJS 单元测试:模拟 getManager 导致“未找到连接“默认””错误【英文标题】:NestJS Unit Testing of the Service: Mocking getManager resulting in 'Connection "default" was not found' error 【发布时间】:2021-08-04 07:04:36 【问题描述】:我目前正在对我的 NestJS 服务进行单元测试。我的实体称为“用户”,我建立了一个基本服务,允许我与 MS SQL 服务器交互,并在我的控制器中建立 GET 和 POST 端点。
我试图模拟的服务方法之一是deleteV2
函数,您可以在下面找到它:
// service file
import Injectable from '@nestjs/common';
import InjectConnection, InjectEntityManager, InjectRepository from '@nestjs/typeorm';
import Connection, createConnection, EntityManager, getConnection, getManager, getRepository, Repository from "typeorm";
import User from '../entities/user.entity';
@Injectable()
export class ServiceName
constructor(@InjectRepository(User) private usersRepository: Repository<User>,
@InjectConnection() private connection: Connection,
@InjectEntityManager() private manager: EntityManager
)
async delete(id: number): Promise<any>
return await this.manager.delete(User, id);
async deleteV2(id: number): Promise<any>
return await getManager().delete(User, id);
请注意,我导入EntityManager
并在我的服务中注入(使用@InjectEntityManager()
)manager: EntityManager
的原因很简单,因为我想要更多练习使用不同的方法(我是一名新实习生与 NestJS 一起工作)。事实上,我在使用注入的manager
的地方定义了delete
方法,然后在我使用导入的getManager
的地方定义了deleteV2
方法,这也是以不同方式练习单元测试的纯粹原因。而我注入Repository、Connection、EntityManager,也是出于同样的原因。
在我的 spec.ts 服务单元测试文件中,我有:
// unit testing file for the service
type MockType<T> =
[P in keyof T]?: jest.Mock<>;
;
describe('service tests', () =>
const mockManagerFactory = jest.fn(() => (
delete: jest.fn().mockReturnValue(undefined),
))
let service: ServiceName;
// mock repository and mock connection also defined similarly to mockManager
let mockManager: MockType<EntityManager>;
beforeEach(async () =>
const module: TestingModule = await Test.createTestingModule(
providers: [
ServiceName,
// tokens for Repository and Connection are also provided along with their respective Factories
provide: getEntityManagerToken(),
useFactory: mockManagerFactory,
,
],
).compile();
service = module.get<ServiceName>(ServiceName);
// mockRepository and mockConnection also defined but not shown
mockManager = module.get(getEntityManagerToken());
);
)
在同一个 spec.ts 文件中,我定义了多个测试。引起问题的是下面涉及deleteV2
的问题:
// same unit testing file for the service
// first test
it('first test', async () =>
expect(await service.delete(1000)).toEqual(undefined);
expect(mockManager.delete).toBeCalled();
);
// second test
it('second test', async () =>
expect(await service.deleteV2(1000)).toEqual(undefined);
expect(mockManager.delete).toBeCalled();
)
虽然第一个测试运行没有问题(第一个测试与服务文件中的delete
关联),但第二个测试(与服务文件中的deleteV2
关联)没有通过并导致以下错误:
● service tests › Service Functions › second test
ConnectionNotFoundError: Connection "default" was not found.
at new ConnectionNotFoundError (error/ConnectionNotFoundError.ts:8:9)
at ConnectionManager.Object.<anonymous>.ConnectionManager.get (connection/ConnectionManager.ts:40:19)
at Object.getManager (index.ts:260:35)
任何想法如何处理这个错误?似乎提供getEntityManagerToken()
与注入的manager
一起使用,但不适用于导入的getManager
,因为deleteV2
使用getManager
而delete
(通过测试)使用导入的manager
【问题讨论】:
【参考方案1】:这就是使用依赖注入的巨大好处所在。@InjectEntityManager()
只是注入(理论上)已经为您设置了连接的对象,您可以使用这些方法而不用担心连接。它使测试变得更加容易(在我看来)。使用getMananger()
,您必须担心 TypeORM 会尝试从当前活动连接中获取实体管理器,而这在测试中不应该存在。您可以使用jest
模拟它,使用类似以下的内容
const deleteMock = jest.fn();
jest.mock('typeorm', () => (
getManager: () => (
delete: deleteMock,
)
))
这很好用,但如果可能的话,我会避免直接从 TypeORM 调用 getConnection
和 getManager
之类的方法。
【讨论】:
看起来不错,但请告诉我如何模拟 @InjectEntityManager()以上是关于服务的 NestJS 单元测试:模拟 getManager 导致“未找到连接“默认””错误的主要内容,如果未能解决你的问题,请参考以下文章