测试基本认知
# 测试基本认知
这节课我们会从以下几个点来介绍和测试相关的基本知识:
- 为什么需要测试 ?
- 有哪些测试 ?
- TDD和BDD项目驱动模式
# 为什么需要测试
测试保证了软件的质量和可靠性,确保我们的软件是按照预期的功能进行的。
- 发现和修复权限
通过测试,我们可以提前发现一些功能不完整、性能低下、有安全漏洞的地方,从而进行一个修复操作。如果一个产品没有经过测试就直接进行交付,那么前面所说到的这些缺陷最终就会在用户使用的时候被暴露出来的,最终就会导致用户的流失。
- 验证软件是否符合需求和标准
在软件开发中,需求和标准的定义往往是通过需求文档、设计文档以及用户操作流程等方式来确定的,那么根据这些文档以及操作流程来编写测试用例,最终测试用例通过,可以间接的说明我们的软件是符合需求和标准的。
- 降低了维护的成本
软件的维护成本是一个非常重要的考虑因素,如果软件存在缺陷和问题,那么软件上线后这些问题才被发现并去修复,整个维护成本会大大的增加的,一般来讲,越到后期,修复一个 Bug 所付出的成本越大,因此通过测试,能够提前帮助开发团队在软件上线之前就发现潜在的问题并进行修复,从而降低了软件的维护成本。
- 增强了整个开发团队的信息
在软件开发领域,有一个词,叫做 Bug破窗效应
指的是软件中如果存在一个Bug,那么这个 Bug 可能会引起一个连锁反应,从而导致一堆的 Bug。
一旦软件中出现 Bug 破窗,就会极大的影响团队的士气,并且整个团队需要为修复这些 Bug 付出极大的时间和精力
- 测试实际上也是遵循软件开发中的最佳实践
无论是哪一种开发模式(瀑布模式、敏捷开发模式、DevOps),测试都是非常重要的一个环节,可以算是一种软件开发的最佳实践,是整个软件开发中不可缺少的一环,进行测试实际上就是在遵循软件开发的最佳实践。
# 哪些测试
整个测试从下往上可以分为 4 类:
- 静态测试
- 单元测试
- 集成测试
- E2E 测试
# 静态测试
静态测试不会涉及到具体的代码的运行,它是在编写代码期间对代码进行一个检查和分析,捕获写代码时可能出现的语法错误或者错别字。
对于前端开发人员来讲,静态测试更倾向于使用 typescript 或者 ESlint 之类的静态检查工具,在编写代码时候就能够提示错误
// 使用 ESLint 的 for-direction 规则能让你更早的发现问题
for (var i = 0; i < 10; i--) {
console.log(i)
}
const two = "2";
// 使用 typescript 的静态检查功能也是能够提前发现问题
const result = add(1, two);
# 单元测试
单元测试往往是验证某一个单独的部分是否能够正常的工作,它是我们软件测试中的最小测试单位,通常是一个函数或者一个方法。单元测试往往是由开发人员来编写一个一个的测试用例,通过一些自动化的工具来进行测试。
// 这是一个函数,该函数是对传入的两个参数做相加操作
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与BDD项目驱动模式
- TDD:英语全称为 Test-Driven Development,翻译成中文就是测试驱动开发
- BDD:英语全称为 Behavior-Driven Development,翻译成中文就是行为驱动开发
这个是软件开发中以测试为中心的两种开发方法论。
# TDD模式
TDD模式是一种以测试为中心的开发方法,强调在编写代码之前先编写测试用例,然后再运行测试用例,如果测试用例失败了,就说明代码有问题,那么就需要修改代码直到所有的测试用例都通过,然后再去编写实际的代码。
- 编写测试用例
const sum = require('../sum');
// 测试用例
test('adds 1 + 2 to equal 3', () => {
expect(sum(1, 2)).toBe(3); // 期望传递 1,2 的时候得到 3
});
// 测试用例
test('adds 0 + 0 to equal 0', () => {
expect(sum(0, 0)).toBe(0); // 期望传递 0,0 的时候得到 0
});
// 测试用例
test('adds -1 + 1 to equal 0', () => {
expect(sum(-1, 1)).toBe(0); // 期望传递 -1, 1 的时候得到 0
});
- 运行测试用例,如果测试用例跑不通,说明代码设计有问题,注意这个时候实际代码是还没有书写的,因此这个时候我们往往会通过一些 mock(模拟) 手段去模拟函数或者模块的实现。
- 编写实际的代码,通过编写实际代码来替换上一步中所用到的 mock 的部分
# BDD模式
BDD是通过行为来驱动软件的开发。这里的行为实际上指的是用户的行为,也就是说 BDD 的模式关注焦点并在在技术实现的细节上面,而是在用户行为和业务上面,更加注重协作和沟通,BDD 的测试用例一般会采用自然语言来进行编写,以便与业务人员和 QA 都能读得懂该测试用例。
BDD 的测试用例一般会采用Given-When-Then 的模式来描述测试场景。
例如下面是一个基于 Given-When-Then 模式的测试用例,假设我们要测试一个登陆页面,这个登陆页面里面包含用户名和密码框以及登陆按钮,测试用例如下:
- Given:用户已经打开登录页面,并且没有输入任何内容
- When:用户输入错误的用户名或密码,然后点击登录按钮
- Then:页面上会显示错误提示信息“用户名或密码错误”
这是一种非常常见的模式,很多中小型企业,在没有使用自动化的测试框架的背景下,往往就是通过这种方式来对软件进行测试。
# 总结
- 为什么需要测试
- 发现和修复缺陷
- 验证软件是否符合需求和标准
- 降低软件的维护成本
- 增强开发团队的信息
- 测试也是软件开发中的一种最佳实践
- 有哪些测试类型
- 静态测试
- 单元测试
- 集成测试
- E2E测试
- TDD和BDD项目驱动模式
- TDD是一种通过编写测试用例来驱动项目开发的模式
- BDD是一种通过描述软件行为来推动项目开发的模式