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

时间:2015-06-30 21:02:35

标签: java unit-testing mocking data-access-layer

假设我在相应的源文件夹/包中有以下类...

[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具体实现以用于测试目的({em> in { {1}}范围)...

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

  2. 另外 中的值(如果有的话) 会在以上单元测试?

  3. ...

    test

    您可以放心地假设... @Mock private Recruiter recR; ... ... public void testGrowTeam( ) { ... expect( recR.srcEmployee( blah) ).andReturn( blah )... // exercising/assertions/validations as usual... } ... 为了上述单元测试的目的,所做的测试中的所有内容都需要它。也就是说,为了简单的答案/解释,没有必要在设置存根和其他方面的设计 what-ifs 中使上述场景过于复杂。

    提前致谢。

1 个答案:

答案 0 :(得分:2)

我对您具体问题的回答:

  1. 在上述单元测试中使用模拟器会是多余的吗?
  2. 由于现在正在编写单元测试,这将是多余的,但我会在下面回答您的第二个问题。

    1. 在上述单元测试中另外做这样的事情会有什么价值(如果有的话)?
    2. 它认为这是您应该进行测试的方式,我建议删除您的存根,RecruiterStandIn。相反,我会设置招募来返回罐头答案,这样你就不必维护两个类只是为了返回一些预定义的数据:

      @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。模拟对象测试允许您测试类之间的交互,并确保事物正确地与周围的世界交互。我认为当你第一次编写类及其相应的测试时,这些测试的价值较低。当一个新的开发人员进来并且无意中你的中断代码因为她不明白需要某些内部行为时,Mock对象测试会在未来一年内发挥作用。

      一个有点人为的例子是,如果让我们说有一辆汽车需要填充汽油:

      public class Car {
            public void fuelUp()
      }
      

      现在通过标准的单元测试,我们会在致电fuelUp()之后检查汽车是否装满汽油,并且从驾驶员那里扣除了适当的金额。但是,由于我们从未测试fuelUp()与周围世界的互动方式,因此很容易做到以下几点:

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

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