我有一个Jest Nest.js控制器测试,可以在其中测试对实时数据库的调用。很好。
我想使用嵌套HTTP Server进行“存根e2e”测试(我正在使用supertest)。但是,当我导入AppModule
时,似乎无法开玩笑来覆盖任何内容。
这是我使用存根类的工作控制器设置。
describe('Working stubbed controller test', () => {
let controller;
beforeAll(async () => {
const moduleFixture = await Test.createTestingModule({
controllers: [MyController],
providers: [
{
provide: ObjectInjectionDependency,
useClass: ObjectInjectionDependency
},
{
provide: '@string/injection/dependency',
useClass: DbOjectMockIAmUsing
},
{
provide: '@another/string/injection/dependency',
useValue: '@another/string/injection/dependency',
},
{
provide: DbConnection,
useValue: {
selectOne: () => null,
selectAll: () => null
}
}
]
})
.compile();
controller = moduleFixture.get<MyController>(MyController)
});
it('/GET url', async () => {
const request = {
method: "GET",
params: {},
query: {}
}
expect(
await controller.all(request)
).toHaveProperty(
'data'
)
});
});
这是我尝试使用supertest
将存根类与HTTP服务器结合在一起的尝试,但未成功。存根类将被忽略。
describe('Bypassing stubs application test', () => {
let app;
let server;
beforeAll(async () => {
const moduleFixture = await Test.createTestingModule({
imports: [AppModule],
providers: [
{
provide: ObjectInjectionDependency,
useClass: ObjectInjectionDependency
},
{
provide: '@string/injection/dependency',
useClass: DbOjectMockIAmUsing
},
{
provide: '@another/string/injection/dependency',
useValue: '@another/string/injection/dependency',
},
{
provide: DbConnection,
useValue: {
selectOne: () => null,
selectAll: () => null
}
}
]
})
.compile();
app = moduleFixture.createNestApplication();
server = app.getHttpServer()
await app.init();
});
it('/GET roots', async () => {
expect(
await request(server).get('/myEndpoint')
).toMatchObject({
'statusCode': 200
})
});
});
我尝试使用overrideProvider()
方法,但它们也不起作用
const moduleFixture = await Test.createTestingModule({
imports: [AppModule]
})
.overrideProvider(ObjectInjectionDependency)
.useClass(ObjectInjectionDependency)
.overrideProvider('@string/injection/dependency')
.useClass(DbOjectMockIAmUsing)
.overrideProvider('@another/string/injection/dependency')
.useValue('@another/string/injection/dependency')
.overrideProvider(DbConnection)
.useValue({
selectOne: () => null,
selectAll: () => null
})
.compile()
我还尝试使用Jest覆盖类
Jest.mock('@path/to/dbconnection', () => {
selectOne: () => null,
selectAll: () => null
}))
一切似乎都没有效果。
我尝试了spyOn()
jest.spyOn(DbConnection, 'selectOne').mockImplementation(() => null);
jest.spyOn(DbConnection, 'selectAll').mockImplementation(() => null);
但是我似乎遇到了一个奇怪的错误
No overload matches this call.
Overload 1 of 4, '(object: typeof DbConnection, method: never): SpyInstance<never, never>', gave the following error.
Argument of type 'string' is not assignable to parameter of type 'never'.
Overload 2 of 4, '(object: typeof DbConnection, method: never): SpyInstance<never, never>', gave the following error.
Argument of type 'string' is not assignable to parameter of type 'never'.ts(2769)
我了解对控制器的测试“足够好”,但是我仍然对自己做错了事感到好奇,因为我确信将来会找到这种测试方法的用例。
编辑:
事实证明,我遇到了两个问题。首先,无论出于什么原因,我都在努力让Jest模拟类的方法。按照@Estus Flask的建议,我现在至少可以使用模拟/存根方法
import { DbConnection } from '@some/path';
jest.spyOn(DbConnection.prototype, 'selectOne').mockReturnValue(null);
第二,几乎所有教程都解释了如何使用显式导入路径进行模拟
import { DbConnection } from '@some/path';
jest.mock('@some/path');
DbConnection.mockReturnValue(null);
省略了有关I discovered from this answer会引起问题的打字稿类型检查的详细信息。
let myMock = <jest.Mock<DbConnection>>DbConnection;
尽管上述初始错误有所不同,但链接答案中的类型转换和示例解决了很多困惑。
尽管如此,鉴于赏金的存在,也许有人可以解释为什么providers
数组包含import
时AppModule
数组被忽略了的原因
答案 0 :(得分:1)
对于遇到此问题的其他人,问题(至少在我的情况下)正在使用
imports: [AppModule]
据我所知,Nest在使用imports
时会自行解决所有依赖关系,并且由于AppModule
是基本上加载所有应用程序依赖关系的模块,因此无论出于何种原因,似乎所有类我在providers
数组中给出的内容将被忽略。
要解决这个问题,我只需要使用我原来的方法,但是像这样调用HTTP服务器
const response = await request(server).get('myUrl');
所以最终结构是
describe('Working stubbed controller test', () => {
let app;
let server;
beforeAll(async () => {
const moduleFixture = await Test.createTestingModule({
controllers: [MyController],
providers: [
ObjectInjectionDependency,
{
provide: '@string/injection/dependency',
useClass: DbOjectMockIAmUsing
},
{
provide: '@another/string/injection/dependency',
useClass: AnotherClassIAmUsing,
},
{
provide: DbConnection,
useValue: {
selectOne: () => null,
selectAll: () => null
}
}
]
})
.compile();
app = moduleFixture.createNestApplication();
server = app.getHttpServer()
await app.init();
});
it('/GET url', async () => {
const response = await request(server).get('myUrl');
expect(response.body.data).toBe('stuff');
});
});
不包括拆卸方法