一、引言
在进行单元测试时,我们经常会遇到对外部资源的依赖,如数据库、网络接口等。模拟(Mocking)和存根(Stubbing)是两种帮助我们模拟这些外部资源,使我们能够在隔离环境中测试单元的方法。在本文中,我们将详细介绍模拟和存根,以及如何在单元测试中使用它们。
二、模拟和存根是什么?
模拟和存根都是用来模拟外部资源的技术,但它们的关注点略有不同:
-
存根(Stubs):存根是用来提供预设行为的。它们在你调用方法时返回一个特定的值或抛出一个异常。
-
模拟(Mocks):模拟不仅提供预设行为,还能检查调用的次数、参数等。通常我们用模拟来验证一个对象是否正确地使用了另一个对象。
三、使用模拟和存根的例子
下面,我们将使用JavaScript中的流行测试库,Jest,来展示如何使用模拟和存根。
例1:使用存根
假设你有一个函数getUserName
,它从数据库中获取用户的名字。你想要测试这个函数,但是不想依赖真实的数据库。
async function getUserName(userId) {
const user = await db.getUser(userId);
return user.name;
}
你可以使用Jest的jest.fn()
方法来创建一个存根:
const db = {
getUser: jest.fn()
};
db.getUser.mockResolvedValue({ name: 'Alice' });
expect(await getUserName(1)).toBe('Alice');
在这个例子中,我们创建了一个存根来代替db.getUser
方法。这个存根总是返回一个具有名字"Alice"的用户。
例2:使用模拟
假设你有一个login
函数,它调用了一个authentication
服务来验证用户的凭据。你想要测试这个函数,但是你更关心它是否正确地调用了authentication
服务。
async function login(username, password) {
return await authentication.authenticate(username, password);
}
你可以使用Jest的jest.fn()
方法来创建一个模拟:
const authentication = {
authenticate: jest.fn()
};
authentication.authenticate.mockResolvedValue(true);
await login('Alice', 'password');
expect(authentication.authenticate).toHaveBeenCalledWith('Alice', 'password');
在这个例子中,我们创建了一个模拟来代替authentication.authenticate
方法。然后,我们使用toHaveBeenCalledWith
方法来验证login
函数是否正确地调用了authentication.authenticate
方法。
四、结论
模拟和存根是单元测试中的重要工具。它们帮助我们创建隔离的测试环境,使我们能够集中测试代码的特定部分,而不必担心其他外部依赖项。
下面是一些更深入使用模拟和存根的示例:
例3:更复杂的存根行为
在有些情况下,你可能想要模拟一些更复杂的行为,例如抛出异常。你可以通过配置存根来实现这一点。
const db = {
getUser: jest.fn()
};
db.getUser.mockRejectedValue(new Error('User not found'));
try {
await getUserName(1);
} catch (e) {
expect(e.message).toBe('User not found');
}
在这个例子中,我们配置存根在被调用时抛出一个错误。然后,我们在测试中捕获这个错误,并验证它的消息是否正确。
例4:模拟函数调用的次数
除了验证模拟函数是否被正确的参数调用,你还可以验证模拟函数被调用的次数。
const authentication = {
authenticate: jest.fn()
};
authentication.authenticate.mockResolvedValue(true);
await login('Alice', 'password');
await login('Bob', 'password');
expect(authentication.authenticate).toHaveBeenCalledTimes(2);
在这个例子中,我们使用toHaveBeenCalledTimes
方法来验证login
函数是否调用了两次authentication.authenticate
方法。
五、结语
模拟和存根是一种强大的工具,可以帮助你编写出更加健壮和可维护的单元测试。通过了解何时以及如何使用这些工具,你可以更有效地测试你的代码,而无需担心外部依赖的复杂性。希望以上的示例可以帮助你在实践中更好地理解和应用模拟和存根。
六、参考链接
-
Jest: https://jestjs.io/
-
Sinon (另一款支持存根和模拟的JavaScript测试库): http://sinonjs.org/
最后:下方这份完整的软件测试视频教程已经整理上传完成,需要的朋友们可以自行领取【保证100%免费】