有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

如果我已经有了存根,java是一个多余的模拟库吗?

假设我在各自的源文件夹/包中有以下类

[src/myApp]
|_Employee «concrete»
|_Manager «abstract» 
|_ManagerImpl «concrete» (Class Under Test)
|_Recruiter «abstract» 
|_RecruiterImpl «concrete» (Collaborator)

public class ManagerImpl implements Manager {
   ...
   private Recruiter recR;
   ...

   public void growTeam( Object criteria ){ 
      //...check preconditions
      Employee newB = recR.srcEmployee( criteria );
      //...whatever else
   }

   ...

} 

[test/myApp]
|_RecruiterStandIn «concrete»
|_ManagerImplTest   

public class RecruiterStandIn implements Recruiter { 

   Map<Object, Employee> reSrcPool = new HashMap<>();

   public RecruiterStandIn( ){ 
      // populate reSrcPool with dummy test data...
   }    

   public Employee srcEmployee( Object criteria ){
      return reSrcPool.get( criteria );
   }
}

public class ManagerImplTest {
   ...
   // Class Under Test
   private ManagerImpl mgr;

   // Collaborator
   private Recruiter recR = new RecruiterStandIn( );
   ...

   public void testGrowTeam(  ) {
      //...
      mgr.setRecruiter( recR ); 
      mgr.growTeam( criteria );
      // assertions follow...
   }

   ...    
}

以下是我的问题:考虑到我在代码库中已经有一个RecruiterStandIn的具体实现,用于测试目的(testscope中)

  1. 在上述单元测试中也使用模拟是多余的吗

  2. 在上述单元测试中执行类似操作时,中的值(如果有)是多少

...
@Mock
private Recruiter recR;
...

...
public void testGrowTeam(  ) { 
   ...
   expect( recR.srcEmployee( blah) ).andReturn( blah )...
   // exercising/assertions/validations as usual...
}
...

您可以放心地假设RecruiterStandIn做了被测类在上述单元测试中所需的一切。也就是说,为了简单的回答/解释,没有必要在存根维护等方面人为地将上述场景过度复杂化

提前谢谢


共 (1) 个答案

  1. # 1 楼答案

    我对你们具体问题的回答是:

    1. 在上述单元测试中也使用模拟会是多余的吗

    由于单元测试是现在编写的,这将是多余的,但我可以看到下面第二个问题的答案

    1. 在上面的单元测试中额外做这样的事情有什么价值(如果有的话)

    它认为这是你应该做测试的方式,我建议你去掉存根。相反,我会设置新兵返回罐装答案,这样你就不必维护两个类来返回一些预定义的数据:

    @Spy
    private Recruiter recR;
    
    public void testGrowTeam(  ) { 
    
         // Setup canned data return
         doReturn(generateTestEmployee()).when(recR).srcEmployee(any(Object.class));
    
        expect( recR.srcEmployee( blah) ).andReturn( blah )...
        // exercising/assertions/validations as usual...
    }
    

    仅供参考上述语法将用于使用Mockito。根据我在你的例子中所能告诉你的,Mockito给了你在不需要你创建新的测试实体的情况下剔除某些部分和更多部分的能力

    原始答案

    当然,你应该做模拟对象测试Mocks Aren't Stubs。模拟对象测试允许您测试类之间的交互,并确保事物与它们周围的世界正确交互。我认为,当您第一次编写类及其相应的测试时,这些测试的价值会降低。一年后,当一个新的开发人员进来时,由于她不明白需要某些内部行为,你的代码在不经意间被破坏了,模拟对象测试就会大放异彩

    一个有点做作的例子是,假设我们有一辆汽车需要加满一些汽油:

    public class Car {
          public void fuelUp()
    }
    

    现在,通过标准的单元测试,我们将检查在调用fuelUp()之后,汽车是否充满了汽油,以及是否从驾驶员那里扣除了适当的金额。但由于我们从未测试过fuelUp()是如何与周围世界互动的,它很容易做到以下几点:

    public void fueldUp() {
        siphonGasFromNearestCar();
        buyCoffeeAndChips()
    }
    

    但是通过模拟对象测试,你可以确保汽车以正确和预期的方式加满油