【问题标题】:How to test a method invocation inside an anonymous class using mockito如何使用 mockito 在匿名类中测试方法调用
【发布时间】:2011-05-05 03:08:31
【问题描述】:
@Transactional(propagation = Propagation.REQUIRED)
    public void exe() {
        try {
            Reserve reserveInfo = newTransactionTemplate.execute(new TransactionCallback<Reserve>() {
                @Override
                public Reserve doInTransaction(TransactionStatus status) {
                    return reserveService.callReserve(reserveDetails);
                }
            });
            if(reserveInfo != null && reserveInfo.getStatus()=="DONE") {
            someOtherService.doSomething();
            }
        } finally {
            if(reserveInfo!= null && reserveInfo.getStatus().equals("DONE")){
                final String id = reserveInfo.getId();                                  
                Release releaseInfo = newTransactionTemplate.execute(new TransactionCallback<Release>() {
                    @Override
                    public Release doInTransaction(TransactionStatus status) {
                        return reserveService.callRelease(id);
                    }
                });             
                if (releaseInfo.getStatus() != "RELEASED") {
                    throw new RuntimeException("Problem in releaseing");

                }
            }
        }       
    }

这是我要测试的示例代码。我在网上测试匿名课程时找不到太多东西。 我想测试 exe() 方法,通过 newTransactionTemplate.execute 方法并模拟对 reserveService.callReserve(reserveDetails) 的调用。

任何机构都可以建议我如何测试这种情况吗?

这是我尝试测试的示例:

 private SomeService someService = null;
    @Mock
    private ReserveService mockReserveService;
    @Mock
    private ReleaseService mockReleaseService;
    @Mock
    private TransactionTemplate mockTransactionTemplate;
    @Mock
    private SomeOtherService mockSomeOtherService;    
    @BeforeMethod
    public void setup() throws Exception {
       MockitoAnnotations.initMocks(this);   
       someService = new SomeService();
       someService.setReserveService(mockReserveService);
       someService.setReleaseService(mockReleaseService);
       someService.setSomeOtherService(mockSomeOtherService);
       someService.setNewTransactionTemplate(mockTransactionTemplate);
    }
    @Test(enabled=true)
    public void exeHappyPath() {
        Reserve reserveInfo = new Reserve();
        reserveInfo.setId("123");
        reserveInfo.setStatus("DONE");
        Release releaseInfo = new Release();
        releaseInfo.setStatus("RELEASED");
        when(mockReserveService.callReserve(Mockito.any(ReserveDetails.class))).thenReturn(reserveInfo);
        when(mockReserveService.callRelease(reserveInfo.getId())).thenReturn(releaseInfo);
        when(mockTransactionTemplate.execute(Mockito.<TransactionCallback<Reserve>>any())).thenReturn(reserveInfo);
        when(mockTransactionTemplate.execute(Mockito.<TransactionCallback<ReleaseInfo>>any())).thenReturn(releaseInfo);
        //Call the exe method
        someService.exe();

        verify(mockReserveService, times(1)).callReserve(Mockito.any(ReserveDetails.class));
        verify(mockReserveService, times(1)).callRelease(reserveInfo.getId())); 
        verify(mockSomeOtherService, times(1)).doSomthing());

    }

第二次调用when(mockTransactionTemplate.execute..返回对象releaseInfo 抛出 java.lang.ClassCastException:

【问题讨论】:

    标签: java mocking mockito


    【解决方案1】:

    这是上述场景的解决方案。因为我对测试 newTransactionTemplate.execute() 的调用不感兴趣,所以它是一个 Spring API。我想测试 reserveService.callReserve(reserveDetails) 和 reserveService.callRelease(id) 的调用。 测试这一点的唯一方法是,如果我们创建一个只是通过的事务模板/事务回调“真实”实现/存根。所以 doIntransaction 方法应该只执行操作。然后我们可以对操作方法设置期望,在这种情况下是 reserveService。

        when(mockTransactionTemplate.execute(Mockito.<TransactionCallback>any())).thenAnswer(new Answer() {
             public Object answer(InvocationOnMock invocation) {
                 Object[] args = invocation.getArguments();
               TransactionCallback arg = (TransactionCallback)args[0];
                 return arg.doInTransaction(new SimpleTransactionStatus());
             }
         });     
        when(mockResourceService.callReserve(any(ReserveDetails.class))).thenReturn(reserveInfo);
        when(mockResourceService.callRelease(eq(id))).thenReturn(releaseInfo);
    
        //Call the exe method
        someService.exe();
    
        verify(mockResourceService, times(1)).callReserve(any(ReserveDetails.class));
        verify(mockSomeOtherService, times(1)).doSomthing());
        verify(mockMemberResourceService, times(1)).callRelease(eq(id)); 
    

    【讨论】:

    • 谢谢安杰。 Java 8 中的这种模拟 when(transactionTemplate.execute(Mockito.&lt;TransactionCallback&gt;any())).thenAnswer((Answer) invocation -&gt; { final TransactionCallback txCallback = (TransactionCallback) invocation.getArguments()[0]; return txCallback.doInTransaction(new SimpleTransactionStatus()); });
    【解决方案2】:

    reserveService 来自哪里?如果您通过 SomeClass 的构造函数或 setter 注入它,则可以改为传递一个 mock。

    // Set up your mock and stub out the method call
    ReserveService reserveService = mock(ReserveService.class);
    when(reserveService.callReserve(any(ReserveDetails.class))).thenReturn(null);
    
    // Inject, either via constructor or setter
    SomeClass instance = new SomeClass(reserveService);
    // Or, instance.setReserveService(reserveService);
    

    【讨论】:

    • 是的..ReserveService是通过属性注入的。
    • Yes..ReserveService 通过属性注入。此测试是否涵盖对同样通过属性注入的 newTransactionTemplate.execte() 方法的调用。
    • ReserveService reserveService = mock(ReserveService.class); TransactionTemplate newTransactionTemplate = mock(TransactionTemplate.class); SomeClass instance = new SomeClass(); instance.setReserveService(reserveService); instance.setNewTransactionTemplate(newTransactionTemplate); 您现在可以致电SomeClass#exe(),但我并不完全适合您。你到底想测试什么?
    • 我试过你刚才提到的,但是对于 newTransactionTemplate.execte() 调用返回 null。我可以将其存根以返回 Reserve 类型,但不会测试 reserveService.callReserve()。我什至可以忍受这一点,但还有一个问题我在代码中以不同的返回类型调用 newTransactionTemplate.execute 两次。这会中断测试,因为 newTransactionTemplate.execute 只是返回类型不同,但方法签名两次都相同。
    • 例如。第一次调用: Reserve reserveInfo = newTransactionTemplate.execute(new TransactionCallback() { @Override public Reserve doInTransaction(TransactionStatus status) { return reserveService.callReserve(reserveDetails); } });第二次调用:Release releaseInfo = newTransactionTemplate.execute(new TransactionCallback() { @Override public Release doInTransaction(TransactionStatus status) { return reserveService.callRelease(id); } });
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-02-03
    • 1970-01-01
    • 2013-06-04
    • 1970-01-01
    • 1970-01-01
    • 2018-06-09
    • 2013-03-16
    相关资源
    最近更新 更多