【问题标题】:How can a Nest Bull queue be tested via Jest (DI via @InjectQueue)?如何通过 Jest 测试 Nest Bull 队列(通过 @InjectQueue 进行 DI)?
【发布时间】:2021-09-13 18:38:37
【问题描述】:

给定一个通过 @InjectQueue 装饰器使用队列的 Injectable:

@Injectable()
export class EnqueuerService {
  constructor (
    @InjectQueue(QUEUE_NAME) private readonly queue: Queue
  ) {
  }

  async foo () {
    return this.queue.add('job')
  }
}

如何测试此服务是否正确调用队列?我可以做基本的脚手架:

describe('EnqueuerService', () => {
  let module: TestingModule
  let enqueuerService: EnqueuerService

  beforeAll(async () => {
    module = await Test.createTestingModule({
      imports: [EnqueuerModule]
    }).compile()
    enqueuerService = module.get(EnqueuerService)

    // Here I'd usually pull in the dependency to test against:
    // queue = module.get(QUEUE_NAME)
    //
    // (but this doesn't work because queue is using the @InjectQueue decorator)
  })

  afterAll(async () => await module.close())

  describe('#foo', () => {
    it('adds a job', async () => {
      await enqueuerService.foo()

      // Something like this would be nice: 
      // expect(queue.add).toBeCalledTimes(1)
      //
      // (but maybe there are alternative ways that are easier?)
    })
  })
})

我对 Nest DI 容器设置非常迷茫,但我怀疑有一些聪明的方法可以做到这一点。但是,尽管尝试了数小时,但我无法取得进展,并且文档对我没有帮助。任何人都可以提供解决方案吗?它没有必须进行模拟,如果更容易创建一个真正的队列来测试那也没关系,我只想按预期验证我的服务排队!任何帮助表示赞赏。

【问题讨论】:

    标签: typescript dependency-injection jestjs mocking nestjs


    【解决方案1】:

    通过查看库,我发现了一个 helper function,它根据其名称创建队列注入令牌:getQueueToken(name?: string)。

    该函数是从库中导出的,因此您可以使用它来为您提供自己的队列实现以进行测试。

    import { getQueueToken } from '@nestjs/bull';
    
    describe('EnqueuerService', () => {
      let module: TestingModule
      let enqueuerService: EnqueuerService
    
      beforeAll(async () => {
        module = await Test.createTestingModule({
          imports: [EnqueuerModule]
        })
          .overrideProvider(getQueueToken(QUEUE_NAME))
          .useValue({ /* mocked queue */ })
          .compile()
    
        enqueuerService = module.get(EnqueuerService)
        queue = module.get(QUEUE_NAME)
      })
    
      afterAll(async () => await module.close())
    
      describe('#foo', () => {
        it('adds a job', async () => {
          await enqueuerService.foo()
    
          expect(queue.add).toBeCalledTimes(1)
        })
      })
    })
    

    编辑

    要检查队列服务调用的方法,您可以在测试文件的根目录创建一个模拟。我重新组织了测试文件,以便在测试设置和测试本身之间进行更清晰的划分:

    let module: TestingModule
    let enqueuerService: EnqueuerService
    let mockQueue;
    
    // Create a helper function to create the app.
    const createApp = async () => {
      module = await Test.createTestingModule({
        imports: [EnqueuerModule]
      })
        .overrideProvider(getQueueToken(QUEUE_NAME))
        .useValue(mockQueue)
        .compile()
    
      enqueuerService = module.get(EnqueuerService)
    }
    
    describe('EnqueuerService', () => {    
      // Recreate app before each test to clean the mock.
      beforeEach(async () => {
        mockQueue = {
          add: jest.fn(),
        };
        await createApp();
      })
    
      afterAll(async () => await module.close())
    
      describe('#foo', () => {
        it('adds a job', async () => {
          await enqueuerService.foo()
    
          // Check calls on the mock.
          expect(queue.add).toBeCalledTimes(1)
        })
      })
    
      describe('#bar', () => {
        // Override the mock for a specific test suite.
        beforeEach(async () => {
          mockQueue.add = jest.fn().mockImplementation(/** */);
          // The mock has changed so we need to recreate the app to use the new value.
          await createApp();
        })
    
        it('adds a job', async () => {
          // ...
        })
      })
    })
    

    【讨论】:

    • 看起来很有希望!我得到了这个错误:Error: Nest could not find queue element,它来自module.get(QUEUE_NAME) 行。 FWIW,如果我完全删除“队列”引用,测试运行(尽管没有断言),所以这里有 something 可以工作,感觉非常接近完全工作。
    • 我添加了一个示例,说明如何在不依赖嵌套检索模拟的情况下模拟队列
    • 非常好,谢谢。 FWIW 我最终使用 jest-mock-extended 创建模拟 (mockQueue = mock<Queue>();)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-11-25
    • 2018-06-03
    • 2017-07-15
    • 2015-04-06
    • 1970-01-01
    • 2018-08-28
    • 2021-07-07
    相关资源
    最近更新 更多