写代码时,单元测试是个好习惯。但很多时候,我们的函数会依赖外部服务,比如调用天气 API、支付接口或者用户登录系统。这时候直接跑测试,速度慢不说,网络一断就报错,根本没法稳定运行。
问题在哪?
举个例子,你写了个方法 checkWeatherStatus(),它会请求某个天气网站的接口,判断今天是否下雨。如果真去发请求,每次测试都得联网,而且万一那个网站抽风,你的测试就挂了——可其实你的逻辑没问题。
单元测试的核心是“隔离”,只测自己的逻辑,不碰外部环境。所以,得想办法把外部依赖“替身”掉。
用 Mock 模拟外部响应
常见的做法是使用 Mock 技术,假装那个接口返回了数据。比如在 Python 的 unittest 中,可以用 unittest.mock.patch 来替换实际的网络请求。
from unittest import mock
import unittest
# 假设这是你要测试的函数
def check_weather_status(city):
response = requests.get(f"https://api.weather.com/v1/{city}")
data = response.json()
return "rain" in data["condition"].lower()
# 测试类
class TestWeather(unittest.TestCase):
@mock.patch('requests.get')
def test_rainy_condition(self, mock_get):
# 设定模拟返回值
mock_get.return_value.json.return_value = {
"condition": "Light Rain"
}
result = check_weather_status("shanghai")
self.assertTrue(result)
这样,测试运行时根本不会真的发请求,而是用你设定的假数据。速度快,还稳定。
前端也能这么做
如果你是写 JavaScript,比如用 Jest 测试一个获取用户信息的函数,也可以 mock 掉 fetch。
global.fetch = jest.fn(() =>
Promise.resolve({
json: () => Promise.resolve({ id: 1, name: '张三' }),
})
);
// 然后测试你的函数
test('should return user name', async () => {
const userData = await fetchUser(1);
expect(userData.name).toBe('张三');
});
这样一来,哪怕服务器没开,测试照样能跑。
别忘了边界情况
除了正常返回,还要考虑网络超时、接口报错、返回空数据这些情况。Mock 的好处就是你能轻松模拟这些“倒霉场景”。
@mock.patch('requests.get')
def test_network_error(self, mock_get):
mock_get.side_effect = requests.exceptions.ConnectionError
with self.assertRaises(ConnectionError):
check_weather_status("beijing")
这种测试平时很难触发,但用 Mock 几行代码就能覆盖,提前发现容错问题。
小技巧:封装外部调用
建议把所有外部请求单独封装成一个模块或类。比如写个 ApiService,专门处理 HTTP 调用。这样测试时只需要 mock 这一层,不用动业务逻辑。
就像修电脑时,你不拆主板,只换插件卡。干净利索,还不影响其他功能。
实际开发中,很多人一开始图省事直接写死请求,结果后期加测试特别麻烦。早点把外部依赖隔离出来,后面省心不少。