我编写了一个自己的 CacheInterceptor 来缓存 POST 请求,并考虑 Accept-Language header 。当然,我想对其进行单元测试,但我不知道如何正确执行此操作,因为 trackBy
方法需要 ExecutionContext
并且该方法使用 httpAdapterHost
和 reflector
字段。
有人以前这样做过并且知道如何实现完整的测试覆盖率吗?
编辑:这是CacheInterceptor的代码
import {
CACHE_KEY_METADATA,
CacheInterceptor,
ExecutionContext,
Injectable,
} from '@nestjs/common';
import { createHash } from 'crypto';
@Injectable()
export class MyCacheInterceptor extends CacheInterceptor {
trackBy(context: ExecutionContext): string | undefined {
const httpAdapter = this.httpAdapterHost.httpAdapter;
const cacheMetadata = this.reflector.get(CACHE_KEY_METADATA, context.getHandler());
const request = context.switchToHttp().getRequest();
return [
cacheMetadata,
httpAdapter.getRequestUrl(request),
JSON.stringify(request.body),
request.headers['accept-language'],
]
.reduce(
(hash, somethingToHash) => (
hash.update(
somethingToHash
? Buffer.from(somethingToHash)
: Buffer.alloc(0)
)
),
createHash('md5'),
)
.digest('hex');
}
}
最佳答案
请记住,以下示例是单独测试拦截器。您的用例可能需要进行一些调整,但总体方法应该是有效的。
- 我将使用构造函数注入(inject)缓存和反射器依赖项:
@Injectable()
export class MyCacheInterceptor extends CacheInterceptor {
constructor(
@Inject(CACHE_MANAGER) protected readonly cacheManager: Cache,
@Inject(Reflector) protected readonly reflector: Reflector
) {
super(cacheManager, reflector);
}
trackBy(context: ExecutionContext): string | undefined {
// ...
// ...
- 您的测试可能如下所示:
describe("MyCacheInterceptor", () => {
let interceptor: MyCacheInterceptor;
beforeEach(async () => {
const module = await Test.createTestingModule({
imports: [CacheModule.register()],
providers: [
{ provide: CACHE_MANAGER, useValue: {} },
{ provide: Reflector, useValue: { get: () => "hello" } },
MyCacheInterceptor,
],
}).compile();
// see issue: https://github.com/nestjs/nest/issues/8076
module.createNestApplication();
interceptor = module.get(MyCacheInterceptor);
});
it("creates", () => {
expect(interceptor).toBeTruthy();
});
it("tracks something", () => {
const mockExecutionContext: ExecutionContext = createMock<ExecutionContext>(
{
getHandler: () => ({}),
switchToHttp: () => ({
getRequest: () => ({
url: "/test-url",
originalUrl: "/test-url",
method: "GET",
body: {
someKey: "someValue",
},
headers: {
"accept-language": "en",
},
}),
}),
}
);
const result = interceptor.trackBy(mockExecutionContext);
expect(result).toBe("d4f8ad8ba612cda9a5fda09cc244120c");
});
});
- 有一种模拟
httpAdapterHost
(以及cacheManager
和reflector
)的方法:
(interceptor["httpAdapterHost"] as any) = {
httpAdapter: { getRequestUrl: () => "hello" },
};
我认为这是一种反模式,因为您不应该 mock /监视内部方法和属性。但是,如果您检查 this GitHub 问题,您会发现没有好的或正确的方法来模拟 HttpAdapterHost
,因此在这种情况下,打破它可能是一个很好的规则。
createMock
来自@golevelup/ts-jest
关于unit-testing - 如何对 NestJS 的自定义 CacheInterceptor 进行单元测试?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72885605/