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 thesetup
hooks.对于简单的服务提供者,您可以摆脱Nestjs工具,创建一个简单的虚假依赖服务,并使用
new
在setup
挂钩中实例化您的服务。
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
将需要一个真正的蒙戈服务器连接,嘲笑createConnection
的mongoose
。
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.
使用beforeAll
和afterAll
启动和停止应用程序,使用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