开发模式
瀑布模式
将软件开发过程视为一系列按顺序进行的阶段,如同瀑布流水一样,每个阶段都有明确的输入和输出,前一个阶段完成后才进入下一个阶段。典型的阶段包括需求分析、设计、编码、测试、维护等
敏捷开发模式
敏捷开发是一种以人为核心、迭代、循序渐进的开发方法。它强调团队与客户的紧密合作,通过一系列短周期的迭代来逐步交付满足用户需求的软件产品。短周期不停迭代
DevOps
DevOps 是一组过程、方法与系统的集合,它旨在打破开发(Development)和运维(Operations)之间的传统壁垒,实现软件的持续集成、持续交付和持续部署。DevOps 将开发、测试、运维等多个环节紧密结合起来,通过自动化工具和流程来提高软件交付的速度和质量。
测试
静态测试
typescript
eslint
单元测试
单元测试往往是验证某一个单独的部分是否能够正常的工作,它是我们软件测试中的最小测试单位,通常是一个函数或者一个方法。单元测试往往是由开发人员来编写一个一个的测试用例,通过一些自动化的工具来进行测试。
// 这是一个函数,该函数是对传入的两个参数做相加操作
function calculateSum(a, b) {
return a + b;
}
// 接下来我们要对上面的函数进行一个测试
describe("calculateSum", function() {
// 这个就是一个测试用例
it("should add two numbers correctly", function() {
expect(calculateSum(1, 2)).toEqual(3); // 期望传入 1,2 的时候得到的值为 3
expect(calculateSum(3, 4)).toEqual(7); // 期望传入 3,4 的时候得到的值为 7
});
});
单元测试由于是对一个函数或者方法进行测试,是独立的一个单元,因此在进行单元测试的时候,往往会屏蔽发送请求,连接数据库等功能,这些功能一般都通过 mock (模拟)的形式来实现。
集成测试
所谓集成测试,就是将多个单元组装起来一起进行测试,主要是看这些单元在一起的时候是否能够正常工作,也就是说,集成测试的目的是确保整个系统中各个部分连接起来是能够正常工作的。
到了集成测试的时候,就会连接真实的数据,发送真实的网络请求,确保它们在协作的时候能够正常的工作。
下面是一个集成测试的例子:
// Express 里面的一个集成测试的示例
const request = require("supertest");
const app = require("./app");
describe("User API", function () {
let userId;
// 测试用例
// 测试添加新的用户,测试的是一个功能,涉及到发送真实的请求
it("should add a new user", function (done) {
request(app)
.post("/users")
.send({ name: "Alice", email: "alice@example.com" })
.expect(201)
.end(function (err, res) {
if (err) return done(err);
userId = res.body.id;
done();
});
});
// ...
});
E2E 测试
End To End,翻译成中文就是端到端的测试。这种测试就会测试整个软件系统的功能以及完整性,这种测试会去模拟用户的行为和软件进行一个交互,相比集成测试,E2E 测试会测试更加完整的功能,更像是一个真实的用户在和软件进行交互。
下面使用一个 E2E 测试的示例:
import {generate} from 'todo-test-utils'
describe('todo app', () => {
it('should work for a typical user', () => {
const user = generate.user()
const todo = generate.todo()
cy.visitApp()
cy.findByText(/register/i).click()
cy.findByLabelText(/username/i).type(user.username)
cy.findByLabelText(/password/i).type(user.password)
cy.findByText(/login/i).click()
cy.findByLabelText(/add todo/i)
.type(todo.description)
.type('{enter}')
cy.findByTestId('todo-0').should('have.value', todo.description)
cy.findByLabelText('complete').click()
cy.findByTestId('todo-0').should('have.class', 'complete')
})
})
上面的代码描述了一个完整的流程,从打开应用程序到注册用户、创建待办事项、完成待办事项、直到最终验证应用程序的状态,这就是一个典型的 E2E 测试,它会验证整个应用程序的功能和用户体验。
项目驱动模式
TDD:英语全称为 Test-Driven Development,翻译成中文就是测试驱动开发
BDD:英语全称为 Behavior-Driven Development,翻译成中文就是行为驱动开发
测试驱动开发
TDD 模式是一种以测试为中心的开发方法,强调在编写代码之前先编写测试用例,然后再运行测试用例,如果测试用例失败了,就说明代码有问题,那么就需要修改代码直到所有的测试用例都通过,然后再去编写实际的代码。
行为驱动开发
BDD 是通过行为来驱动软件的开发。这里的行为实际上指的是用户的行为,也就是说 BDD 的模式关注焦点在用户行为和业务上面,更加注重协作和沟通,BDD 的测试用例一般会采用自然语言来进行编写,以便与业务人员和 QA 都能读得懂该测试用例。
BDD 的测试用例一般会采用 Given-When-Then 的模式来描述测试场景。
例如下面是一个基于 Given-When-Then 模式的测试用例,假设我们要测试一个登陆页面,这个登陆页面里面包含用户名和密码框以及登陆按钮,测试用例如下:
Given:用户已经打开登录页面,并且没有输入任何内容
When:用户输入错误的用户名或密码,然后点击登录按钮
Then:页面上会显示错误提示信息“用户名或密码错误”
这是一种非常常见的模式,很多中小型企业,在没有使用自动化的测试框架的背景下,往往就是通过这种方式来对软件进行测试。
自动化测试
了解了上面所介绍的软件开发模型之后,那么自动化的概念也就非常好懂了。自动化测试属于 DevOps 开发模式里面的一个阶段,主要就是指对新的代码通过一些自动化工具和测试框架进行一个全自动的测试操作。测试通过之后,进入下一个步骤。
测试框架
前面我们介绍过测试有不同的类型,不同的测试框架会有不同的测试重点,比如有的偏向于单元测试,有的偏向于 E2E 测试。
Jest:是一个由 Facebook 开发的 JavaScript 测试框架。它可以用于测试 React 应用程序,也可以用于测试其他类型的 JavaScript 应用程序。它具有简单易用、快速执行、自动化断言等特点。
Mocha:是一个功能强大的 JavaScript 测试框架,可用于测试任何类型的 JavaScript 应用程序。它支持多种测试风格(如 BDD 和 TDD),具有丰富的插件和扩展功能。
Jasmine:是一个行为驱动的 JavaScript 测试框架,提供了一个易于阅读和编写测试的语法。它可以运行在浏览器和 Node.js 环境中,具有自动化断言、Spy 等功能。
Cypress:是一个现代化的自动化测试工具,专注于端到端的功能测试。它具有简单易用、快速执行、可靠性高、可视化测试等特点,支持 Chrome、Firefox、Edge 等多个浏览器。
Puppeteer:是一个由 Google 开发的 Node.js 库,Puppeteer 基于 Chrome DevTools 协议开发,可以完全控制 Chromium 或 Chrome 浏览器,包括页面的加载、截图、交互等操作。Puppeteer 提供了一套稳定的 API,可以确保测试结果的可靠性和一致性。另外,Puppeteer 不仅可以用于自动化测试,还可以用于爬虫、性能测试、页面截图等各种场景。
后面我们会选择 Jest 这个老牌的测试框架进行介绍。
Jest 是由 Facebook 开发的一个 js 测试框架,jest 主要侧重于被用于做单元测试和集成测试,特点如下:
Jest 的特点包括:
简单易用:Jest 的 API 简单易用,测试用例编写起来非常简单。
快速执行:Jest 使用并发执行,可以大大缩短测试时间。
自动化断言:Jest 自带了一个断言库,可以自动化地对测试结果进行断言。
Mock 支持:Jest 支持 Mock,可以方便地模拟各种场景,例如网络请求、计时器等。
Snapshot 测试:Jest 支持 Snapshot 测试,可以方便地对组件的渲染结果进行比较和验证。
集成测试支持:Jest 支持集成测试,可以方便地测试整个应用程序的功能。