Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/350.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如果我已经有存根,模拟库是多余的吗?_Java_Unit Testing_Mocking_Data Access Layer - Fatal编程技术网

Java 如果我已经有存根,模拟库是多余的吗?

Java 如果我已经有存根,模拟库是多余的吗?,java,unit-testing,mocking,data-access-layer,Java,Unit Testing,Mocking,Data Access Layer,假设我在各自的源文件夹/包中有以下类 [src/myApp] |_Employee «concrete» |_Manager «abstract» |_ManagerImpl «concrete» (Class Under Test) |_Recruiter «abstract» |_RecruiterImpl «concrete» (Collaborator) 以下是我的问题:鉴于我有一个招聘人员标准的具体实现,它已经存在于代码库中,用于测试目的(在测试范围内) 在上述单元测试中

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

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

以下是我的问题:鉴于我有一个
招聘人员标准
的具体实现,它已经存在于代码库中,用于测试目的(在
测试
范围内)

  • 在上述单元测试中也使用模拟是否多余?

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

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


    提前感谢。

    我对您具体问题的回答:

  • 在上述单元测试中也使用模拟是否多余?
  • 由于单元测试是现在编写的,所以它是多余的,但是我可以看到下面第二个问题的答案

  • 在上述单元测试中额外执行类似操作的价值(如果有的话)是什么?
  • 它认为这是你应该做测试的方式,我建议你扔掉你的存根,
    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给了你在不需要你创建新的测试实体的情况下剔除某些部分和更多部分的能力

    原始答案

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

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

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

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

    但通过模拟对象测试,您可以确保车辆以正确和预期的方式加注。

    谢谢tkeE2036。我已经被嘲弄了。不过还是要感谢你的布道。我仍然很感激对我的问题的答案——我认为你忽略了这个问题。如果你发现我的文章有帮助,请考虑接受它来帮助未来的人:)冒着不领情的风险,如果我的问题是,“我应该做模拟对象测试吗?”那么你就对钱了。如果我的注意力集中在“路上”的某段时间,那么你就要打1000球了。然而,事实上,我现在只关注上面的例子。我特别想问的是,鉴于上面的例子,使用mock是否是多余的。只是。正如我在我的帖子中所说,正如我现在所写的,这是多余的。我接着说,我会去掉你的存根,使用一个框架来创建你的存根,即使你永远不想做模拟测试。精彩的后续!我将您对Q2的回答理解为“值是,您不必维护两个类来返回一些预定义的数据”。对吗?但你指的是哪两类<代码>招聘人员必须留下<代码>员工必须留下。我可以看到失去了一门课(
    RecruiterStandIn
    )。但是,你认为第二个输的是哪一个呢?
    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...
       }
    
       ...    
    }
    
    ...
    @Mock
    private Recruiter recR;
    ...
    
    ...
    public void testGrowTeam(  ) { 
       ...
       expect( recR.srcEmployee( blah) ).andReturn( blah )...
       // exercising/assertions/validations as usual...
    }
    ...
    
    @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...
    }
    
    public class Car {
          public void fuelUp()
    }
    
    public void fueldUp() {
        siphonGasFromNearestCar();
        buyCoffeeAndChips()
    }