【问题标题】:How to test NestJs response interceptor如何测试 NestJs 响应拦截器
【发布时间】:2021-11-22 08:20:08
【问题描述】:

我尝试关注this thread,但一直收到错误消息。

transform-response.interceptor.ts:

import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { ApiResponseInterface } from '@walletxp/shared-interfaces';

@Injectable()
export class TransformResponseInterceptor<T>
  implements NestInterceptor<T, ApiResponseInterface<Record<string, unknown>>>
{
  intercept(context: ExecutionContext, next: CallHandler): Observable<ApiResponseInterface<Record<string, unknown>>> {
    return next.handle().pipe(map((data) => ({ success: true, data })));
  }
}

为了测试,transform-response.interceptor.spec.ts:

import { TransformResponseInterceptor } from './transform-response.interceptor';
const interceptor = new TransformResponseInterceptor();

const executionContext: any = {
  switchToHttp: jest.fn().mockReturnThis(),
  getRequest: jest.fn().mockReturnThis(),
};

const callHandler = {
  handle: jest.fn(),
};

describe('ResponseInterceptor', () => {
  it('should be defined', () => {
    expect(interceptor).toBeDefined();
  });
  describe('#intercept', () => {
    it('t1', async () => {
      (executionContext.switchToHttp().getRequest as jest.Mock<any, any>).mockReturnValueOnce({
        body: { data: 'mocked data' },
      });
      callHandler.handle.mockResolvedValueOnce('next handle');
      const actualValue = await interceptor.intercept(executionContext, callHandler);
      expect(actualValue).toBe('next handle');
      expect(executionContext.switchToHttp().getRequest().body).toEqual({
        data: 'mocked data',
        addedAttribute: 'example',
      });
      expect(callHandler.handle).toBeCalledTimes(1);
    });
  });
});

我的目标是模拟从控制器返回的数据,并检查它在通过拦截器后是否等于我想要的格式化数据。

【问题讨论】:

    标签: typescript http jestjs nestjs interceptor


    【解决方案1】:

    我已经测试了我的拦截器,使用对应用程序的调用,更像是端到端测试。

    import { Test, TestingModule } from '@nestjs/testing';
    import * as request from 'supertest';
    import { INestApplication, HttpStatus } from '@nestjs/common';
    
    import { EmulatorHeadersInterceptor } from '@LIBRARY/interceptors/emulator-headers.interceptor';
    
    import { AppModule } from '@APP/app.module';
    
    describe('Header Intercepter', () => {
        let app: INestApplication;
    
        afterAll(async () => {
            await app.close();
        });
    
        beforeAll(async () => {
            const moduleFixture: TestingModule = await Test.createTestingModule({
                imports: [AppModule],
            }).compile();
    
            app = moduleFixture.createNestApplication();
            app.useGlobalInterceptors(new EmulatorHeadersInterceptor());
            await app.init();
        });
    
        it('./test (PUT) should have the interceptor data', async () => {
            const ResponseData$ = await request(app.getHttpServer())
                .put('/test')
                .send();
    
            expect(ResponseData$.status).toBe(HttpStatus.OK);
            expect(ResponseData$.headers['myheader']).toBe('interceptor');
        });
    });
    

    我的拦截器正在添加一个标头字段,但是对于您的拦截器,您可以将我正在使用的标头拦截器替换为您的拦截器。从那里,您可以测试响应是否包含您想要的内容。

    【讨论】:

    • 嗨,谢谢,这按预期工作。只有一个问题,这是测试的好习惯吗?我觉得我们正在测试“/test”路由控制器,而不是直接测试拦截器。它确实有效,但我想知道这种测试拦截器的方式是否用于企业项目。
    • 好问题。我只在较小的项目上使用 NestJS,我读过的其他文章说,将这些测试留给集成(e2e),基本上就是这样。我希望您可以通过对 NestJS 内部工作原理的更多了解直接对其进行测试,但这似乎适用于我的项目。
    【解决方案2】:

    如果您正在寻找一个简单的单元测试,那么您需要了解 RxJS 如何用于异步测试。像下面这样的东西可以工作:

    describe('ResponseInterceptor', () => {
      let interceptor: ResponseInterceptor;
    
      beforeEach(() => {
        interceptor = new ResponseInterceptor();
      });
    
      it('should map the data', (done) => {
        // this sets up a mock execution context (which you don't use so it's blank)
        // and a mock CallHandler that returns a known piece of data 'test data'
        const obs$ = interceptor.intercept({} as any, { handle: () => of('test data') });
        // this tests the observable, and calls done when it is complete
        obs$.subscribe({
          next: (val) => {
            expect(val).toEqual({ success: true, data: 'test data' })
          }),
          complete: () => done()
        })
      });
    
    });
    

    【讨论】:

    • 谢谢,一定会更多地研究 RxJS。
    猜你喜欢
    • 2022-10-14
    • 2020-01-03
    • 2020-04-24
    • 1970-01-01
    • 2021-04-10
    • 2020-08-30
    • 2022-10-13
    • 2021-07-15
    • 2021-02-11
    相关资源
    最近更新 更多