第2章 应用层协议实战:从单元测试看HTTP、FTP与DNS
1. HTTP协议单元测试实战HTTP协议作为应用层最核心的协议之一其单元测试主要围绕状态码、请求方法、头部字段等关键要素展开。在实际项目中我经常使用Python的requests库配合unittest框架进行测试。比如测试一个返回JSON数据的API端点时通常会验证以下内容import unittest import requests class TestUserAPI(unittest.TestCase): def test_get_user(self): # 测试正常请求 response requests.get(https://api.example.com/users/1) self.assertEqual(response.status_code, 200) self.assertEqual(response.headers[Content-Type], application/json) # 测试资源不存在的情况 response requests.get(https://api.example.com/users/999) self.assertEqual(response.status_code, 404) # 测试请求方法不被允许 response requests.post(https://api.example.com/users/1) self.assertEqual(response.status_code, 405)在测试HTTP缓存机制时需要特别注意Cache-Control和ETag头部。我曾经遇到过因为缓存配置不当导致用户看到过期数据的案例。通过以下测试可以验证缓存行为def test_cache_control(self): # 第一次请求应该返回200 response requests.get(https://api.example.com/products/1) self.assertEqual(response.status_code, 200) # 带If-None-Match头的请求 headers {If-None-Match: response.headers[ETag]} response requests.get(https://api.example.com/products/1, headersheaders) self.assertEqual(response.status_code, 304) # 未修改2. FTP协议测试关键点FTP协议测试需要特别关注连接模式主动/被动、文件传输完整性和权限控制。在自动化测试中我推荐使用Python的ftplib库。下面是一个测试文件上传下载完整性的例子from ftplib import FTP import hashlib def test_ftp_transfer(): ftp FTP(ftp.example.com) ftp.login(usertest, passwdpassword) # 测试文件上传 with open(testfile.txt, rb) as f: ftp.storbinary(STOR testfile.txt, f) # 验证文件完整性 local_hash hashlib.md5(open(testfile.txt,rb).read()).hexdigest() remote_hash hashlib.md5(ftp.retrbinary(RETR testfile.txt)).hexdigest() assert local_hash remote_hash # 清理测试文件 ftp.delete(testfile.txt) ftp.quit()FTP的权限测试也很重要我曾经因为权限配置错误导致生产环境文件被意外覆盖。可以通过以下方式测试def test_ftp_permissions(): ftp FTP(ftp.example.com) ftp.login(userreadonly, passwdpassword) # 测试写权限 try: with open(testfile.txt, rb) as f: ftp.storbinary(STOR testfile.txt, f) assert False, Write should be forbidden except error_perm: assert True3. DNS协议测试方法论DNS协议测试主要关注解析准确性、响应时间和缓存行为。使用dig命令可以快速测试但在自动化测试中Python的dnspython库更实用import dns.resolver def test_dns_resolution(): # 测试A记录解析 answers dns.resolver.resolve(example.com, A) assert len(answers) 0 for rdata in answers: assert str(rdata).count(.) 3 # 验证IPv4格式 # 测试MX记录 answers dns.resolver.resolve(example.com, MX) assert len(answers) 0DNS缓存测试是个容易忽略的点。我曾经遇到过一个因TTL设置过长导致DNS切换延迟的问题。可以通过以下方式测试def test_dns_caching(): # 第一次查询 start_time time.time() dns.resolver.resolve(example.com, A) first_query_time time.time() - start_time # 立即再次查询 start_time time.time() dns.resolver.resolve(example.com, A) second_query_time time.time() - start_time # 缓存查询应该更快 assert second_query_time first_query_time * 0.54. 协议测试的通用模式虽然HTTP、FTP和DNS是不同的协议但它们的测试有一些通用模式连接测试验证协议能否建立基本连接错误处理测试协议对异常情况的处理性能基准测量协议操作的响应时间安全性验证协议的安全特性在构建测试框架时我通常会抽象出这些通用模式。例如一个协议测试基类可能包含class ProtocolTestBase(unittest.TestCase): def test_connection(self): 测试协议连接 raise NotImplementedError def test_invalid_input(self): 测试异常输入处理 raise NotImplementedError def test_performance(self): 测试基本性能 raise NotImplementedError对于需要模拟网络环境的测试可以使用像responses这样的库来mock HTTP请求import responses responses.activate def test_mock_http(): responses.add(responses.GET, https://api.example.com/users/1, json{id: 1, name: John}, status200) response requests.get(https://api.example.com/users/1) assert response.json()[name] John在实际项目中协议测试往往会遇到各种边界情况。比如测试HTTP分块传输时需要特别处理Transfer-Encoding头测试FTP大文件传输时要注意网络中断的恢复能力。这些经验都是在踩过坑之后才积累起来的。
