测试与发布
测试与发布
自动化测试被视为任何认真的软件开发工作的重要组成部分。自动化使得在开发过程中快速,轻松地重复单个测试或测试套件变得容易。这有助于确保发行版符合质量和性能目标。自动化有助于扩大覆盖范围,并为开发人员提供更快的反馈循环。自动化既可以提高单个开发人员的生产率,又可以确保测试在关键的开发生命周期关头运行,例如源代码控制检入,功能集成和版本发布。
此类测试通常涉及多种类型,包括单元测试,端到端(e2e)测试,集成测试等等。虽然好处是毋庸置疑的,但设置这些好处可能很繁琐。
- 自动为组件提供默认的单元测试和为应用程序提供端到端测试。
- 提供默认工具(例如构建独立模块
/ 应用程序加载器的测试运行器) 。 - 开箱即用地提供与
Jest 和Supertest 的集成,同时与测试工具无关。 - 使
Nest 依赖项注入系统可在测试环境中使用,以轻松模拟组件。
如前所述,您可以使用自己喜欢的任何测试框架,因为
单元测试
在以下示例中,我们测试了两个类:
describe("CatsController", () => {
let catsController: CatsController;
let catsService: CatsService;
beforeEach(() => {
catsService = new CatsService();
catsController = new CatsController(catsService);
});
describe("findAll", () => {
it("should return an array of cats", async () => {
const result = ["test"];
jest.spyOn(catsService, "findAll").mockImplementation(() => result);
expect(await catsController.findAll()).toBe(result);
});
});
});
由于上面的示例是微不足道的,因此我们并未真正测试任何特定于
测试工具
@nestjs/testing
软件包提供了一组实用程序,这些实用程序可实现更强大的测试过程。让我们使用内置的
describe("CatsController", () => {
let catsController: CatsController;
let catsService: CatsService;
beforeEach(async () => {
const module = await Test.createTestingModule({
controllers: [CatsController],
providers: [CatsService]
}).compile();
catsService = module.get<CatsService>(CatsService);
catsController = module.get<CatsController>(CatsController);
});
describe("findAll", () => {
it("should return an array of cats", async () => {
const result = ["test"];
jest.spyOn(catsService, "findAll").mockImplementation(() => result);
expect(await catsController.findAll()).toBe(result);
});
});
});
createTestingModule()
方法,该方法将模块元数据对象作为其参数(与传递给 @Module()
装饰器的对象相同NestFactory.create()
在常规
除了使用任何提供程序的生产版本,您还可以使用自定义提供程序覆盖它以进行测试。例如,您可以模拟数据库服务而不是连接到实时数据库。我们将在下一部分中介绍替代,但是它们也可用于单元测试。
端到端测试
与侧重于单个模块和类的单元测试不同,端到端(e2e)测试涵盖了更汇总级别的类和模块的交互
describe("Cats", () => {
let app: INestApplication;
let catsService = { findAll: () => ["test"] };
beforeAll(async () => {
const module = await Test.createTestingModule({
imports: [CatsModule]
})
.overrideProvider(CatsService)
.useValue(catsService)
.compile();
app = module.createNestApplication();
await app.init();
});
it(`/GET cats`, () => {
return request(app.getHttpServer())
.get("/cats")
.expect(200)
.expect({
data: catsService.findAll()
});
});
afterAll(async () => {
await app.close();
});
});
在此示例中,我们以前面描述的一些概念为基础。除了我们之前使用的
我们使用get('/ cats')
将向
在此示例中,我们还提供了
每个重写方法都会使用
- useClass:您提供了一个将实例化的类,以提供实例来覆盖对象(提供者,保护者等
) 。 - useValue:您提供一个将覆盖该对象的实例。
- useFactory:提供一个函数,该函数返回将覆盖该对象的实例。
数据库测试
我们也可以在集成测试中对数据库进行测试:
let app: INestApplication;
beforeAll(async () => {
const module = await Test.createTestingModule({
imports: [
UserModule,
// Use the e2e_test database to run the tests
TypeOrmModule.forRoot({
type: "postgres",
host: "localhost",
port: 5432,
username: "username",
password: "",
database: "e2e_test",
entities: ["./**/*.entity.ts"],
synchronize: false
})
]
}).compile();
app = module.createNestApplication();
await app.init();
});
afterAll(async () => {
await app.close();
});
具体的测试用例可以编写如下:
let repository: Repository<User>;
beforeAll(async () => {
// ...
// Add this line at the end of the beforeAll method
repository = module.get("UserRepository");
});
afterEach(async () => {
await repository.query(`DELETE FROM users;`);
});
describe("GET /users", () => {
it("should return an array of users", async () => {
// Pre-populate the DB with some dummy users
await repository.save([{ name: "test-name-0" }, { name: "test-name-1" }]);
// Run your end-to-end test
const { body } = await supertest
.agent(app.getHttpServer())
.get("/users")
.set("Accept", "application/json")
.expect("Content-Type", /json/)
.expect(200);
expect(body).toEqual([
{ id: expect.any(Number), name: "test-name-0" },
{ id: expect.any(Number), name: "test-name-1" }
]);
});
});