Jestjs NestJs请求和响应拦截器单元测试

Jestjs NestJs请求和响应拦截器单元测试,jestjs,nestjs,Jestjs,Nestjs,我想为我的API记录传入请求和传出响应。我创建了一个请求拦截器和一个响应拦截器,如下所述 因此请求拦截器只记录请求对象 @Injectable() export class RequestInterceptor implements NestInterceptor { private readonly logger: Logger = new Logger(RequestInterceptor.name, true); public intercept(context: Execut

我想为我的API记录传入请求和传出响应。我创建了一个请求拦截器和一个响应拦截器,如下所述

因此请求拦截器只记录请求对象

@Injectable()
export class RequestInterceptor implements NestInterceptor {
  private readonly logger: Logger = new Logger(RequestInterceptor.name, true);

  public intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    const { originalUrl, method, params, query, body } = context.switchToHttp().getRequest();

    this.logger.debug({ originalUrl, method, params, query, body }, this.intercept.name);

    return next.handle();
  }
}
@Injectable()
导出类RequestInterceptor实现了NestInterceptor{
私有只读记录器:记录器=新记录器(RequestInterceptor.name,true);
公共截获(上下文:ExecutionContext,下一步:CallHandler):可观察{
const{originalUrl,method,params,query,body}=context.switchToHttp().getRequest();
debug({originalUrl,method,params,query,body},this.intercept.name);
返回next.handle();
}
}
响应拦截器等待传出响应,稍后记录状态代码和响应对象

@Injectable()
export class ResponseInterceptor implements NestInterceptor {
  private readonly logger: Logger = new Logger(ResponseInterceptor.name, true);

  public intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    const { statusCode } = context.switchToHttp().getResponse();

    return next.handle().pipe(
      tap((responseData: any) =>
        this.logger.debug({ statusCode, responseData }, this.intercept.name),
      ),
    );
  }
}
@Injectable()
导出类响应Interceptor实现NestInterceptor{
专用只读记录器:记录器=新记录器(ResponseInterceptor.name,true);
公共截获(上下文:ExecutionContext,下一步:CallHandler):可观察{
const{statusCode}=context.switchToHttp().getResponse();
返回next.handle().pipe(
点击((响应数据:任何)=>
this.logger.debug({statusCode,responseData},this.intercept.name),
),
);
}
}
我想测试他们,但不幸的是,我几乎没有测试经验。我试着从请求拦截器开始,然后想出了这个

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

const nextCallHander: CallHandler<any> = {
  handle: jest.fn(),
};

describe('RequestInterceptor', () => {
  let interceptor: RequestInterceptor;

  beforeEach(() => {
    interceptor = new RequestInterceptor();
  });

  describe('intercept', () => {
    it('should fetch the request object', (done: any) => {
      const requestInterception: Observable<any> = interceptor.intercept(executionContext, nextCallHander);

      requestInterception.subscribe({
        next: value => {
          // ... ??? ...
        },
        error: error => {
          throw error;
        },
        complete: () => {
          done();
        },
      });
    });
  });
});
const executionContext: any = {
  switchToHttp: jest.fn().mockReturnThis(),
  getResponse: jest.fn().mockReturnThis()
};

const nextCallHander: CallHandler<any> = {
  handle: jest.fn()
};

describe("ResponseInterceptor", () => {
  let interceptor: ResponseInterceptor;

  beforeEach(() => {
    interceptor = new ResponseInterceptor();
  });

  describe("intercept", () => {
    it("should fetch the statuscode and response data", (done: any) => {
      const responseInterception: Observable<any> = interceptor.intercept(
        executionContext,
        nextCallHander
      );

      responseInterception.subscribe({
        next: value => {
          // ...
        },
        error: error => {
          throw error;
        },
        complete: () => {
          done();
        }
      });
    });
  });
});
const executionContext:any={
switchToHttp:jest.fn().mockReturnThis(),
getRequest:jest.fn().mockReturnThis(),
};
const nextCallHander:CallHandler={
句柄:jest.fn(),
};
描述('RequestInterceptor',()=>{
let拦截器:请求拦截器;
在每个之前(()=>{
拦截器=新请求拦截器();
});
描述('intercept',()=>{
它('应该获取请求对象',(done:any)=>{
const requestInterception:Observable=interceptor.intercept(executionContext,nextCallHander);
requestInterception.subscribe({
下一步:值=>{
// ... ??? ...
},
错误:错误=>{
投掷误差;
},
完成:()=>{
完成();
},
});
});
});
});
我目前不知道下一个回调应该传递什么,但当我尝试按原样运行测试时,它会说requestInterception变量未定义。因此,测试在到达下一个回调之前失败。所以我得到的错误信息是

TypeError:无法读取未定义的属性“subscribe”

我还试着测试响应拦截器,并得出了这个结论

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

const nextCallHander: CallHandler<any> = {
  handle: jest.fn(),
};

describe('RequestInterceptor', () => {
  let interceptor: RequestInterceptor;

  beforeEach(() => {
    interceptor = new RequestInterceptor();
  });

  describe('intercept', () => {
    it('should fetch the request object', (done: any) => {
      const requestInterception: Observable<any> = interceptor.intercept(executionContext, nextCallHander);

      requestInterception.subscribe({
        next: value => {
          // ... ??? ...
        },
        error: error => {
          throw error;
        },
        complete: () => {
          done();
        },
      });
    });
  });
});
const executionContext: any = {
  switchToHttp: jest.fn().mockReturnThis(),
  getResponse: jest.fn().mockReturnThis()
};

const nextCallHander: CallHandler<any> = {
  handle: jest.fn()
};

describe("ResponseInterceptor", () => {
  let interceptor: ResponseInterceptor;

  beforeEach(() => {
    interceptor = new ResponseInterceptor();
  });

  describe("intercept", () => {
    it("should fetch the statuscode and response data", (done: any) => {
      const responseInterception: Observable<any> = interceptor.intercept(
        executionContext,
        nextCallHander
      );

      responseInterception.subscribe({
        next: value => {
          // ...
        },
        error: error => {
          throw error;
        },
        complete: () => {
          done();
        }
      });
    });
  });
});
const executionContext:any={
switchToHttp:jest.fn().mockReturnThis(),
getResponse:jest.fn().mockReturnThis()
};
const nextCallHander:CallHandler={
句柄:jest.fn()
};
描述(“响应接收器”,()=>{
let拦截器:应答器;
在每个之前(()=>{
侦听器=新的响应侦听器();
});
描述(“截取”,()=>{
它(“应该获取状态码和响应数据”,(完成:任何)=>{
const responseInterception:Observable=拦截器.interception(
执行上下文,
下一个呼叫器
);
responseInterception.subscribe({
下一步:值=>{
// ...
},
错误:错误=>{
投掷误差;
},
完成:()=>{
完成();
}
});
});
});
});
这一次,我在拦截器上遇到了一个错误

TypeError:无法读取未定义的属性“pipe”

能帮我测试一下这两个拦截器吗


提前感谢

测试拦截器可能是测试NestJS应用程序最具挑战性的部分之一,因为
ExecutionContext
并从
next
返回正确的值

让我们从
ExecutionContext
开始:

您已经用当前上下文设置好了,重要的是如果您正在使用HTTP(就像您一样),那么您有一个
switchToHttp()
方法,并且
switchToHttp()
返回的任何内容都有一个
getResponse()
getRequest()
方法(如果两者都使用)。在那里,
getRequest()
getResponse()
方法应该返回从req和res使用的值,例如
res.statusCode
req.originalUrl
。我喜欢将传入和传出放在同一个拦截器上,因此我的
context
对象通常如下所示:

const context={
switchToHttp:jest.fn(()=>({
getRequest:()=>({
原文如下:“/”,
方法:“GET”,
参数:未定义,
查询:未定义,
正文:未定义,
}),
getResponse:()=>({
状态代码:200,
}),
})),
//我最近需要的方法,所以我想我应该添加它
getType:jest.fn(()=>“http”)
}
这只是保持了上下文的轻巧和易于处理。当然,您始终可以根据日志记录的需要,用更复杂的值替换这些值

现在来看有趣的部分,
CallHandler
对象。
CallHandler
有一个
handle()
函数,该函数返回一个可观察的值。至少,这意味着您的
下一个
对象需要如下所示:

const next={
句柄:()=>共()个
}
但这是非常基本的,对记录响应或处理响应映射没有多大帮助。为了使处理程序功能更健壮,我们可以始终执行以下操作

const next={
handle:jest.fn(()=>of(myDataObject)),
}
现在,如果需要,可以通过Jest重写函数,但一般来说,这就足够了。现在,您的
next.handle()
将返回一个可观察值,并将通过RxJS操作符执行pipable操作

现在,为了测试可观察性,您的