繁体   English   中英

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

[英]Nest.js Jest cannot mock testing app but can mock testing controller

我有一个 Jest Nest.js 控制器测试,我可以在其中存根对实时数据库的调用。 它工作正常。

我想使用嵌套 HTTP 服务器进行“存根 e2e”测试(我使用的是超级测试)。 但是,当我导入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);

遗漏了我从这个答案中发现的导致问题的打字稿类型检查的细节。

let myMock = <jest.Mock<DbConnection>>DbConnection;

虽然上述初始错误有所不同,但链接答案中的类型转换和示例解决了很多困惑。

尽管如此,鉴于有赏金,也许有人可以解释为什么当import数组包含AppModule时, providers数组几乎被忽略

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

imports: [AppModule]

据我所知,Nest 在使用imports时会自行解决所有依赖项,并且由于AppModule是基本上加载所有应用程序依赖项的模块,似乎无论出于何种原因,我在providers数组中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');
    });
});

不包括拆卸方法

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM