ahm*_*hri 9 java unit-testing design-patterns mocking mockito
我有以下课程:
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*/
}
}
Run Code Online (Sandbox Code Playgroud)
此类表示自我使用,因为其公共方法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());
}
Run Code Online (Sandbox Code Playgroud)
虽然之前的解决方案解决了这个问题,但不推荐使用该spy方法的javadoc :
像往常一样,您将阅读部分模拟警告:面向对象编程通过将复杂性划分为单独的特定SRPy对象来解决复杂性问题.部分模拟如何适应这种范式?嗯,它只是没有...部分模拟通常意味着复杂性已被移动到同一对象上的不同方法.在大多数情况下,这不是您想要设计应用程序的方式.
该deleteOrganization方法的复杂性已经转移到deleteUser方法,这是由类自用引起的.除了In most cases, this is not the way you want to design your application声明之外,不建议使用此解决方案的事实表明存在代码异味,并且确实需要重构来改进此代码.
如何删除这个自用?是否有可以应用的设计模式或重构技术?
合同里是不是deleteOrganization()说User那个组织里的所有s也会被删除?
如果确实如此,那么您必须至少保留部分删除用户逻辑,deleteOrganization()因为您的类的客户端可能依赖于该功能。
在讨论选项之前,我还要指出,每个删除方法都是非最终的public,并且类和方法都不是最终的。这将使某人扩展该类并覆盖可能危险的方法。
解决方案 1 - 删除组织仍需删除其用户
考虑到我对首要危险的评论,我们删除了实际删除用户的部分deleteUser()。我假设公共方法deleteUser会执行额外的验证,也许还会执行deleteOrganization().
public void deleteOrganization(Organization organization)
{
/*Delete organization*/
/*Delete related users*/
for (User user : organization.getUsers()) {
privateDeleteUser(user);
}
}
private void privateDeleteUser(User user){
//actual delete logic here, without anything delete organization doesn't need
}
public void deleteUser(User user)
{
//do validation
privateDeleteUser(user);
//perform any extra business locic
}
Run Code Online (Sandbox Code Playgroud)
deleteUser()这会重新使用执行删除操作的实际代码,并避免子类更改为不同行为的危险。
解决方案 2 - 不需要在 deleteOrganization() 方法中删除用户
如果我们不需要一直从组织中删除用户,我们可以从deleteOrganization() 中删除这部分代码。在我们也需要删除用户的少数地方,我们可以像现在的deleteOrganization 一样执行循环。由于它使用公共方法,因此只有任何客户端都可以调用它们。我们也可以将逻辑提取到一个Service类中。
public void DeleteOrganizationService(){
private MyClass myClass;
...
public void delete(Organization organization)
{
myClass.deleteOrganization(organization);
/*Delete related users*/
for (User user : organization.getUsers()) {
myClass.deleteUser(user);
}
}
}
Run Code Online (Sandbox Code Playgroud)
这是更新的MyClass
public void deleteOrganization(Organization organization)
{
/*Delete organization only does not modify users*/
}
public void deleteUser(User user)
{
/*same as before*/
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
397 次 |
| 最近记录: |