如何正确模拟一个简单的 CRUD 界面?
How do I mock a simple CRUD interface correctly?
假设我有以下简单的示例界面:
public interface UserDB {
void addUser(User user);
void updateUser(User user);
User getUser(String id);
void deleteUser(String id);
}
我想用 Mockito 编写测试来测试简单的 CRUD 操作。我想验证以下内容:
- Update/get/delete 仅当用户之前使用 'add'
添加时有效
- 如果用户在 'delete' 之前被删除,它们将失败。
- 已经创建的用户无法再次创建
- 等等
我的想法是,我需要这样的东西:
UserDB udb = mock(UserDB.class);
when(udb.getUser("1")).thenThrow(new UserNotFoundException());
when(udb.addUser(new User("1"))).when(udb.getUser("1").thenReturn(new User("1"));
但是,像最后一行这样的东西不是正确的 Mockito 语法。对于不同的先决条件或调用的方法的不同顺序,我如何检查验证不同的结果?
这样做是一种代码味道。事实上,您想编写所有这些代码来查看 "user cannot be added twice" 是否真的基本上只是编写一个新的 class,这与您的数据库规则无关。
这是一个你可以做的事情的想法;将验证规则构建为数据库上的 Decorator,然后使用模拟 "undecorated" 数据库测试装饰器本身。例如:
public class ValidatingUserDB implements UserDB {
private UserDB delegate;
public ValidatingUserDB(UserDB delegate) {
this.delegate = delegate;
}
public void addUser(User user) {
User oldUser = delegate.get(user.getId());
if (oldUser != null) throw new IllegalArgumentException(
"User " + user.getId() + " already exists!";
delegate.addUser(user);
}
}
然后,您将像这样编写测试:
@Test(expected=IllegalArgumentException.class)
public void testNoDuplicateUsers() {
User sampleUser = new User("1");
UserDB delegate = mock(UserDB.class);
when(delegate.getUser(any(User.class))).thenReturn(sampleUser);
UserDB db = new ValidatingUserDB(delegate);
db.addUser(sampleUser);
}
public void testAddingUser() {
User sampleUser = new User("1");
UserDB delegate = mock(UserDB.class);
UserDB db = new ValidatingUserDB(delegate);
db.addUser(sampleUser);
verify(delegate).getUser(sampleUser);
verify(delegate).addUser(sampleUser);
}
通过将验证行为与 CRUD 行为分开,您可以自己编写测试,而无需使用超级复杂的答案规则等重写所有这些测试。
假设我有以下简单的示例界面:
public interface UserDB {
void addUser(User user);
void updateUser(User user);
User getUser(String id);
void deleteUser(String id);
}
我想用 Mockito 编写测试来测试简单的 CRUD 操作。我想验证以下内容:
- Update/get/delete 仅当用户之前使用 'add' 添加时有效
- 如果用户在 'delete' 之前被删除,它们将失败。
- 已经创建的用户无法再次创建
- 等等
我的想法是,我需要这样的东西:
UserDB udb = mock(UserDB.class);
when(udb.getUser("1")).thenThrow(new UserNotFoundException());
when(udb.addUser(new User("1"))).when(udb.getUser("1").thenReturn(new User("1"));
但是,像最后一行这样的东西不是正确的 Mockito 语法。对于不同的先决条件或调用的方法的不同顺序,我如何检查验证不同的结果?
这样做是一种代码味道。事实上,您想编写所有这些代码来查看 "user cannot be added twice" 是否真的基本上只是编写一个新的 class,这与您的数据库规则无关。
这是一个你可以做的事情的想法;将验证规则构建为数据库上的 Decorator,然后使用模拟 "undecorated" 数据库测试装饰器本身。例如:
public class ValidatingUserDB implements UserDB {
private UserDB delegate;
public ValidatingUserDB(UserDB delegate) {
this.delegate = delegate;
}
public void addUser(User user) {
User oldUser = delegate.get(user.getId());
if (oldUser != null) throw new IllegalArgumentException(
"User " + user.getId() + " already exists!";
delegate.addUser(user);
}
}
然后,您将像这样编写测试:
@Test(expected=IllegalArgumentException.class)
public void testNoDuplicateUsers() {
User sampleUser = new User("1");
UserDB delegate = mock(UserDB.class);
when(delegate.getUser(any(User.class))).thenReturn(sampleUser);
UserDB db = new ValidatingUserDB(delegate);
db.addUser(sampleUser);
}
public void testAddingUser() {
User sampleUser = new User("1");
UserDB delegate = mock(UserDB.class);
UserDB db = new ValidatingUserDB(delegate);
db.addUser(sampleUser);
verify(delegate).getUser(sampleUser);
verify(delegate).addUser(sampleUser);
}
通过将验证行为与 CRUD 行为分开,您可以自己编写测试,而无需使用超级复杂的答案规则等重写所有这些测试。