【发布时间】:2015-07-16 14:08:22
【问题描述】:
我有以下课程:
public class MyClass
{
public void deleteOrganization(Organization organization)
{
/*Delete organization*/
/*Delete related users*/
for (User user : organization.getUsers()) {
deleteUser(user);
}
}
public void deleteUser(User user)
{
/*Delete user logic*/
}
}
这个类代表一个自用,因为它的公共方法deleteOrganization使用它的另一个公共方法deleteUser。在我的例子中,这个类是我开始添加单元测试的遗留代码。因此,我首先针对第一个方法 deleteOrganization 添加了一个单元测试,最后发现该测试已扩展为也可以测试 deleteUser 方法。
问题
问题是这个测试不再是孤立的(它应该只测试deleteOrganization 方法)。我必须处理与deleteUser方法相关的不同条件才能通过它才能通过测试,这极大地增加了测试的复杂性。
解决方案
解决方案是监视被测类并存根 deleteUser 方法:
@Test
public void shouldDeleteOrganization()
{
MyClass spy = spy(new MyClass());
// avoid invoking the method
doNothing().when(spy).deleteUser(any(User.class));
// invoke method under test
spy.deleteOrganization(new Organization());
}
新问题
虽然前面的解决方案解决了问题,但不推荐,因为spy方法的javadoc声明:
像往常一样,您将阅读部分模拟警告:对象 面向编程通过划分 将复杂性分解为单独的、特定的 SRPy 对象。怎么偏 模拟适合这种范式吗?好吧,它只是没有......部分模拟 通常意味着复杂性已转移到不同的方法 在同一个物体上。在大多数情况下,这不是您想要的方式 设计您的应用程序。
deleteOrganization 方法的复杂性已移至deleteUser 方法,这是由于类自用造成的。不推荐这个方案,除了In most cases, this is not the way you want to design your application语句,说明代码有异味,确实需要重构来改进这个代码。
这个自用怎么去掉?是否有可以应用的设计模式或重构技术?
【问题讨论】:
-
@ahmehri 与您的问题没有直接关系,但您为什么要先删除组织,然后再删除用户?不应该反过来吗?删除所有用户,然后删除组织。
-
@CKing 这是一个以这种方式实现的遗留代码(与使用的业务逻辑有关)。
标签: java unit-testing design-patterns mocking mockito