目录
UT
Unit Test,单元测试
测试对象:最小的可测试单元(函数、方法、类)
测试范围:单个代码单元的内部逻辑
测试人员:开发人员
测试时机:编码阶段
实现方法:
python
# Python unittest 示例
import unittest
def add(a, b):
return a + b
class TestAddFunction(unittest.TestCase):
def test_add_positive(self):
self.assertEqual(add(2, 3), 5)
def test_add_negative(self):
self.assertEqual(add(-1, -1), -2)
def test_add_zero(self):
self.assertEqual(add(0, 5), 5)
# C++ Google Test 示例
#include <gtest/gtest.h>
int multiply(int a, int b) {
return a * b;
}
TEST(MultiplyTest, PositiveNumbers) {
EXPECT_EQ(multiply(3, 4), 12);
}
TEST(MultiplyTest, WithZero) {
EXPECT_EQ(multiply(0, 5), 0);
EXPECT_EQ(multiply(7, 0), 0);
}
实现工具:
- Python: unittest, pytest
- Java: JUnit, TestNG
- C++: Google Test, Catch2
- JavaScript: Jest, Mocha
- Go: testing package
最佳实践:
- 测试隔离:每个测试独立,不依赖外部资源
- 快速执行:测试应在毫秒级别完成
- 高覆盖率:追求80%+的代码覆盖率
FIRST原则:
- Fast(快速)
- Independent(独立)
- Repeatable(可重复)
- Self-validating(自验证)
- Timely(及时)
IT
Integration Test,集成测试
测试对象:模块/组件之间的接口和交互
测试范围:多个单元的集成
测试人员:开发人员/测试工程师
测试时机:单元测试之后
实现方法:
python
# 数据库集成测试示例
import pytest
import sqlite3
class DatabaseService:
def __init__(self, db_path):
self.conn = sqlite3.connect(db_path)
def add_user(self, username, email):
cursor = self.conn.cursor()
cursor.execute("INSERT INTO users (username, email) VALUES (?, ?)",
(username, email))
self.conn.commit()
return cursor.lastrowid
def get_user(self, user_id):
cursor = self.conn.cursor()
cursor.execute("SELECT * FROM users WHERE id = ?", (user_id,))
return cursor.fetchone()
@pytest.fixture
def db_service(tmp_path):
# 创建临时数据库
db_path = tmp_path / "test.db"
conn = sqlite3.connect(db_path)
conn.execute("""
CREATE TABLE users (
id INTEGER PRIMARY KEY,
username TEXT NOT NULL,
email TEXT NOT NULL
)
""")
conn.commit()
conn.close()
return DatabaseService(db_path)
def test_user_crud(db_service):
# 测试完整的CRUD流程
user_id = db_service.add_user("testuser", "test@example.com")
assert user_id == 1
user = db_service.get_user(user_id)
assert user[1] == "testuser"
assert user[2] == "test@example.com"
实现工具:
- API测试: Postman, Insomnia, RestAssured
- 数据库测试: Testcontainers, DBUnit
- 消息队列测试: Testcontainers with Kafka/RabbitMQ
- 微服务测试: Pact, WireMock
测试类型:
- Big Bang:所有模块一起集成测试
- Top-Down:从顶层开始向下集成
- Bottom-Up:从底层开始向上集成
- Sandwich:结合自上而下和自下而上
ST
System Test,系统测试
测试对象:完整的软件系统
测试范围:端到端功能、性能、安全等
测试人员:测试工程师/QA团队
测试时机:集成测试之后
实现方法:
python
python
# 电商系统测试示例
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
import time
class TestEcommerceSystem:
def setup_method(self):
self.driver = webdriver.Chrome()
self.driver.implicitly_wait(10)
def test_complete_purchase_flow(self):
# 1. 访问网站
self.driver.get("https://example-shop.com")
# 2. 搜索商品
search_box = self.driver.find_element(By.NAME, "q")
search_box.send_keys("笔记本电脑")
search_box.send_keys(Keys.RETURN)
# 3. 选择商品
product = self.driver.find_element(By.CSS_SELECTOR, ".product-list li:first-child")
product.click()
# 4. 添加到购物车
add_to_cart = self.driver.find_element(By.ID, "add-to-cart")
add_to_cart.click()
# 5. 结账
self.driver.find_element(By.LINK_TEXT, "去结算").click()
# 6. 填写收货信息
self.driver.find_element(By.ID, "address").send_keys("测试地址")
self.driver.find_element(By.ID, "phone").send_keys("13800138000")
# 7. 提交订单
self.driver.find_element(By.ID, "submit-order").click()
# 8. 验证订单创建成功
success_msg = self.driver.find_element(By.CLASS_NAME, "order-success")
assert "订单创建成功" in success_msg.text
def teardown_method(self):
self.driver.quit()
测试类型:
- 功能测试:验证系统功能是否符合需求
- 性能测试:负载测试、压力测试、耐久测试
- 安全测试:渗透测试、漏洞扫描
- 兼容性测试:不同浏览器、操作系统、设备
- 可用性测试:用户体验测试
实现工具:
- Web UI测试: Selenium, Cypress, Playwright
- 移动端测试: Appium, Espresso, XCUITest
- 性能测试: JMeter, Gatling, Locust
- 安全测试: OWASP ZAP, Burp Suite
- API E2E测试: Karate, RestAssured
DT
Development Test,开发测试
这是一个不太标准的术语,通常有两种解释:
解释1:开发阶段的测试(Development Testing)
包含所有开发过程中的测试活动:
text
┌─────────────────────────────────────────────┐
│ Development Testing │
├─────────────┬─────────────┬─────────────────┤
│ Unit Test │ IT │ System Test │
│ (UT) │ │ (ST) │
└─────────────┴─────────────┴─────────────────┘
解释2:开发人员测试(Developer Testing)
开发人员在编码阶段进行的各种测试:
- 单元测试(UT)
- 集成测试(IT的一部分)
- 代码审查
- 静态代码分析
- 契约测试
实现方法(开发测试流程):
python
python
# 完整的开发测试流程示例
import pytest
from unittest.mock import Mock, patch
import requests
# 1. 单元测试
def calculate_discount(price, discount_rate):
if price < 0 or discount_rate < 0 or discount_rate > 1:
raise ValueError("Invalid input")
return price * (1 - discount_rate)
# 2. 集成测试(与外部服务)
class PaymentService:
def __init__(self, api_url):
self.api_url = api_url
def process_payment(self, amount, card_token):
response = requests.post(
f"{self.api_url}/payments",
json={"amount": amount, "card_token": card_token}
)
response.raise_for_status()
return response.json()
# 3. 模拟和契约测试
def test_payment_service_integration():
with patch('requests.post') as mock_post:
# 模拟支付网关响应
mock_response = Mock()
mock_response.json.return_value = {"status": "success", "id": "pay_123"}
mock_response.raise_for_status = Mock()
mock_post.return_value = mock_response
service = PaymentService("https://api.payment.com")
result = service.process_payment(100, "tok_123")
assert result["status"] == "success"
mock_post.assert_called_once()
# 4. 端到端测试(简化版)
def test_e2e_checkout():
# 模拟用户完整流程
cart = ShoppingCart()
cart.add_item("item1", 2)
payment = PaymentProcessor()
result = payment.process(cart.total(), "test_card")
assert result.success
assert cart.is_empty()
完整的测试金字塔模型
text
/\
/ \ E2E/ST (少量)
/ \
/------\ Integration Tests (中等)
/
/---------\ Unit Tests (大量)
/____________\
各层测试比例建议:
- UT: 70-80%
- IT: 10-20%
- ST/E2E: 5-10%
实现框架对比
测试类型 推荐框架 测试速度 维护成本 隔离性
UT pytest, JUnit, Google Test 快 低 高
IT Testcontainers, WireMock 中 中 中
ST Selenium, Cypress, JMeter 慢 高 低
现代测试策略
- 测试驱动开发(TDD)
python
# 1. 先写测试
def test_divide():
assert divide(10, 2) == 5
assert divide(10, 0) raises ZeroDivisionError
# 2. 实现功能
def divide(a, b):
if b == 0:
raise ZeroDivisionError("Cannot divide by zero")
return a / b
# 3. 重构优化
- 行为驱动开发(BDD)
bash
gherkin
# feature文件
Feature: 用户登录
Scenario: 成功登录
Given 用户访问登录页面
When 输入有效的用户名和密码
Then 显示欢迎信息
Scenario: 登录失败
Given 用户访问登录页面
When 输入错误的密码
Then 显示错误消息
- 契约测试(微服务架构)
java
java
// 消费者驱动契约
@Pact(consumer = "OrderService", provider = "PaymentService")
public RequestResponsePact createPaymentPact(PactDslWithProvider builder) {
return builder
.given("payment service is available")
.uponReceiving("a request to process payment")
.path("/payments")
.method("POST")
.willRespondWith()
.status(200)
.body(new PactDslJsonBody()
.stringType("status", "success")
.stringType("transactionId"))
.toPact();
}
CI/CD 中的测试流水线
yaml
yaml
# .gitlab-ci.yml 示例
stages:
- test
unit_tests:
stage: test
script:
- pytest tests/unit/ --cov=src --cov-report=xml
integration_tests:
stage: test
script:
- docker-compose up -d # 启动依赖服务
- pytest tests/integration/
- docker-compose down
system_tests:
stage: test
script:
- npm run e2e # 运行端到端测试
only:
- main # 只在主分支运行系统测试
最佳实践总结
对于 UT:
✅ 使用依赖注入便于mock
✅ 每个测试一个断言
✅ 测试异常和边界情况
❌ 避免测试私有方法
❌ 不要依赖外部服务
对于 IT:
✅ 使用测试数据库(内存数据库或容器)
✅ 测试真实的集成点
✅ 清理测试数据
❌ 避免测试UI层
❌ 不要测试外部服务的内部逻辑
对于 ST:
✅ 模拟真实用户场景
✅ 包含性能和安全测试
✅ 在不同环境中测试
❌ 避免过多的E2E测试
❌ 不要依赖不稳定的外部服务
对于整个测试策略:
- 自动化一切可以自动化的测试
- 保持测试快速反馈
- 测试应该在CI/CD中自动运行
- 测试代码和产品代码同等重要
- 定期重构和维护测试代码
记住:UT是基础,IT是桥梁,ST是保障。良好的测试策略应该平衡这三者,形成稳定的测试金字塔。