服务的 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 使用getManagerdelete(通过测试)使用导入的manager

【问题讨论】:

【参考方案1】:

这就是使用依赖注入的巨大好处所在。@InjectEntityManager() 只是注入(理论上)已经为您设置了连接的对象,您可以使用这些方法而不用担心连接。它使测试变得更加容易(在我看来)。使用getMananger(),您必须担心 TypeORM 会尝试从当前活动连接中获取实体管理器,而这在测试中不应该存在。您可以使用jest 模拟它,使用类似以下的内容

const deleteMock = jest.fn();
jest.mock('typeorm', () => (
  getManager: () => (
    delete: deleteMock,
  )
))

这很好用,但如果可能的话,我会避免直接从 TypeORM 调用 getConnectiongetManager 之类的方法。

【讨论】:

看起来不错,但请告诉我如何模拟 @InjectEntityManager()

以上是关于服务的 NestJS 单元测试:模拟 getManager 导致“未找到连接“默认””错误的主要内容,如果未能解决你的问题,请参考以下文章

如何在服务nestjs中模拟getMongoRepository

使用 NestJS 服务单元测试未找到连接“默认”

NestJS如何在单元测试中创建新的猫鼬模型?

使用注入对 NestJS 控制器进行单元测试

如何开玩笑模拟nestjs导入?

带有模拟存储库的 Nestjs 服务测试不起作用