测试nestjs应用程序

In the previous posts, I have write a lot of testing codes to verify if our application is working as expected.

在之前的文章中,我编写了许多测试代码来验证我们的应用程序是否按预期工作。

Nestjs provides integration with with Jest and Supertest out-of-the-box, and testing harness for unit testing and end-to-end (e2e) test.

Nestjs提供与集成玩笑Supertest外的现成,以及用于单元测试和端-端(E2E)测试被测试的线束。

Nestjs测试工具 (Nestjs test harness)

Like the Angular ‘s TestBed, Nestjs provide a similar Test facilities to assemble the Nestjs components for your testing codes.

像Angular的TestBed ,Nestjs提供了类似的Test工具来为您的测试代码组装Nestjs组件。

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
...
],
}).compile(); service = module.get<UserService>(UserService);
});

Similar to the attributes in the @Module decorator, creatTestingModule defines the components that will be used in the tests.

@Module装饰器中的属性类似, creatTestingModule定义将在测试中使用的组件。

We have demonstrated the methods to test a service in Nestjs applications, eg. in the post.service.spec.ts.

例如,我们已经演示了在Nestjs应用程序中测试服务的方法。 在post.service.spec.ts

To isolate the dependencies in a service, there are several approaches.

为了隔离服务中的依赖关系,有几种方法。

  • Create a fake service to replace the real service, assemble it in the providers .

    创建一个伪造的服务来替换真实的服务,然后在providers组装。

  • providers: [ { provide: UserService, useClass: FakeUserService } ],

    提供者:[{提供:UserService,useClass:FakeUserService}],
  • Use a mock instance instead.

    请改用模拟实例。
  • providers: [ provide: UserService, useValue: { send: jest.fn() } ],

    providers: [ provide: UserService, useValue: { send: jest.fn() } ],

  • For simple service providers, you can escape from the Nestjs harness, and create a simple fake dependent service, and use new to instantize your service in the setup hooks.

    对于简单的服务提供者,您可以摆脱Nestjs工具,创建一个简单的虚假依赖服务,并使用newsetup挂钩中实例化您的服务。

You can also import a module in Test.createTestingModule.

您也可以在Test.createTestingModule导入模块。

Test.createTestingModule({
imports: []
})

To replace some service in the imported modules, you can override it.

要替换导入模块中的某些服务,您可以override它。

Test.createTestingModule({
imports: []
})
.override(...)

笑话技巧和窍门 (Jest Tips and Tricks)

Nestjs testing is heavily dependent on Jest framework. I have spent a lot of time to research testing all components in Nestjs applications.

Nestjs测试在很大程度上依赖于Jest框架。 我花了很多时间来研究测试Nestjs应用程序中的所有组件。

模拟外部类或函数 (Mocking external classes or functions)

For example the mongoose.connect will require a real mongo server to connect, to mock the createConnection of mongoose.

例如, mongoose.connect将需要一个真正的蒙戈服务器连接,嘲笑createConnectionmongoose

Set up mocks before importing it.

在导入之前设置模拟。

jest.mock('mongoose', () => ({
createConnection: jest.fn().mockImplementation(
(uri:any, options:any)=>({} as any)
),
Connection: jest.fn()
}))//...
import { Connection, createConnection } from 'mongoose';
//

When a database provider is instantized, assert the createConnection is called.

实例化数据库提供程序时,断言createConnection被调用。

it('connect is called', () => {
//expect(conn).toBeDefined();
//expect(createConnection).toHaveBeenCalledTimes(1); // it is 2 here. why?
expect(createConnection).toHaveBeenCalledWith("mongodb://localhost/blog", {
useNewUrlParser: true,
useUnifiedTopology: true,
//see: https://mongoosejs.com/docs/deprecations.html#findandmodify
useFindAndModify: false
});
})

通过原型模拟父类 (Mock parent classes through prototype)

Have a look at the local auth guard tests.

看看本地身份验证保护测试。

Mock the method canActivate in the parent prototype.

在父原型中模拟方法canActivate

describe('LocalAuthGuard', () => {
let guard: LocalAuthGuard;
beforeEach(() => {
guard = new LocalAuthGuard();
});
it('should be defined', () => {
expect(guard).toBeDefined();
});
it('should return true for `canActivate`', async () => {
AuthGuard('local').prototype.canActivate = jest.fn(() =>
Promise.resolve(true),
);
AuthGuard('local').prototype.logIn = jest.fn(() => Promise.resolve());
expect(await guard.canActivate({} as ExecutionContext)).toBe(true);
});});

将功能尽可能地提取到功能中 (Extract the functionality into functions as possible)

Let’s have a look at the user.model.ts. Extract the pre save hook method and custom comparePassword method into standalone functions.

让我们看一下user.model.ts 。 将pre save hook方法和自定义comparePassword方法提取到独立函数中。

async function preSaveHook(next) {  // Only run this function if password was modified
if (!this.isModified('password')) return next(); // Hash the password
const password = await hash(this.password, 12);
this.set('password', password); next();
}UserSchema.pre<User>('save', preSaveHook);function comparePasswordMethod(password: string): Observable<boolean> {
return from(compare(password, this.password));
}UserSchema.methods.comparePassword = comparePasswordMethod;

It is easy to test them like simple functions.

像简单功能一样测试它们很容易。

describe('preSaveHook', () => {
test('should execute next middleware when password is not modified', async () => {
const nextMock = jest.fn();
const contextMock = {
isModified: jest.fn()
};
contextMock.isModified.mockReturnValueOnce(false);
await preSaveHook.call(contextMock, nextMock);
expect(contextMock.isModified).toBeCalledWith('password');
expect(nextMock).toBeCalledTimes(1);
}); test('should set password when password is modified', async () => {
const nextMock = jest.fn();
const contextMock = {
isModified: jest.fn(),
set: jest.fn(),
password: '123456'
};
contextMock.isModified.mockReturnValueOnce(true);
await preSaveHook.call(contextMock, nextMock);
expect(contextMock.isModified).toBeCalledWith('password');
expect(nextMock).toBeCalledTimes(1);
expect(contextMock.set).toBeCalledTimes(1);
});
});

端到端测试 (End-to-end testing)

Nestjs integrates supertest to send a request to the server side.

Nestjs集成了超级测试,以将请求发送到服务器端。

Use beforeAll and afterAll to start and stop the application, use request to send a http request to the server and assert the response result.

使用beforeAllafterAll启动和停止应用程序,使用request将http请求发送到服务器并声明响应结果。

import * as request from 'supertest';
//...describe('API endpoints testing (e2e)', () => {
let app: INestApplication;
beforeAll(async () => {
const moduleFixture: TestingModule = await Test.createTestingModule({
imports: [AppModule],
}).compile(); app = moduleFixture.createNestApplication();
app.enableShutdownHooks();
app.useGlobalPipes(new ValidationPipe());
await app.init();
}); afterAll(async () => {
await app.close();
}); // an example of using supertest request.
it('/posts (GET)', async () => {
const res = await request(app.getHttpServer()).get('/posts').send();
expect(res.status).toBe(200);
expect(res.body.length).toEqual(3);
});
}

More details for the complete e2e tests, check Nestjs ‘s test folder.

有关完整的e2e测试的更多详细信息,请检查Nestjs的测试文件夹

翻译自: https://medium.com/@hantsy/testing-nestjs-applications-546ab3e9fa13

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值