Nest.js Jest无法模拟测试应用程序,但可以模拟测试控制器

问题描述

我有一个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],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,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数组包含importAppModule数组被忽略了的原因

解决方法

对于遇到此问题的其他人,问题(至少在我的情况下)正在使用

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');
    });
});

不包括拆卸方法

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...