我使用 Moq 来模拟我的存储库。但是,最近有人说他们更喜欢创建存储库接口的硬编码测试实现。
每种方法的优缺点是什么?
编辑:通过指向 Fowler 的链接阐明了存储库的含义。
我通常会看到存储库的两种情况。我要求一些东西,我得到它,或者我要求一些东西,它不存在。
如果您正在模拟您的存储库,这意味着您的被测系统 (SUT) 正在使用您的存储库。因此,您通常希望测试您的 SUT 在从存储库中获得对象时是否正确运行。而且您还想测试它是否正确地处理了当您期望取回某些东西而没有取回或不确定您是否要取回某些东西时的情况。
如果您正在进行集成测试,硬编码的测试替身是可以的。比如说,你想保存一个对象,然后取回它。但这是在测试两个对象的交互,而不仅仅是 SUT 的行为。他们是两个不同的东西。如果您开始编写虚假存储库,则还需要对它们进行单元测试,否则您最终会将代码的成功和失败建立在未经测试的代码上。
这就是我对 Mocking vs. Test Doubles 的看法。
信噪比:
“你称自己为仓库?我见过容量更大的火柴盒!”
我假设“存储库”是指DAO;如果不是,那么这个答案将不适用。
最近我一直在做我的 DAO 的“内存中”“模拟”(或测试)实现,它基本上是根据传递给模拟构造函数的数据(列表、地图等)进行操作的。这样,单元测试类可以自由地输入测试所需的任何数据,可以更改它等,而不会强制对“内存中”DAO 上运行的所有单元测试进行编码以使用相同的测试数据。
我在这种方法中看到的一个优点是,如果我有十几个单元测试需要使用相同的 DAO 进行测试(例如,注入到被测类中),我不需要记住所有的每次测试数据的详细信息(就像“模拟”被硬编码一样) - 单元测试自己创建测试数据。不利的一面是,这意味着每个单元测试都必须花费几行代码来创建和连接它的测试数据;但这对我来说是一个小缺点。
代码示例:
public interface UserDao {
User getUser(int userid);
User getUser(String login);
}
public class InMemoryUserDao implements UserDao {
private List users;
public InMemoryUserDao(List users) {
this.users = users;
}
public User getUser(int userid) {
for (Iterator it = users.iterator(); it.hasNext();) {
User user = (User) it.next();
if (userid == user.getId()) {
return user;
}
}
return null;
}
public User getUser(String login) {
for (Iterator it = users.iterator(); it.hasNext();) {
User user = (User) it.next();
if (login.equals(user.getLogin())) {
return user;
}
}
return null;
}
}