如何使用mockito测试匿名类中的方法调用

17
@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 异常。
2个回答

18
以下是对上述场景的解决方案。因为我对测试 newTransactionTemplate.execute() 的调用不感兴趣,它只是一个Spring API。我想要测试的是 reserveService.callReserve(reserveDetails)reserveService.callRelease(id) 的调用。 唯一的测试方法是创建一个 TransactionTemplate/TransactionCallback “真实” 实现/桩,该实现只是通过执行操作来完成。然后我们可以对操作方法设置期望,在这种情况下就是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)); 

1
谢谢Anj。这是Java 8中的模拟 when(transactionTemplate.execute(Mockito.<TransactionCallback>any())).thenAnswer((Answer) invocation -> { final TransactionCallback txCallback = (TransactionCallback) invocation.getArguments()[0]; return txCallback.doInTransaction(new SimpleTransactionStatus()); }); - Vijay Nandwana

1

reserveService 是从哪里来的?如果你是通过 SomeClass 的构造函数或者 setter 注入它,那么你可以传递一个模拟对象。

// 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是通过属性注入的。 - Anj
ReserveService reserveService = mock(ReserveService.class); TransactionTemplate newTransactionTemplate = mock(TransactionTemplate.class);SomeClass instance = new SomeClass(); instance.setReserveService(reserveService); instance.setNewTransactionTemplate(newTransactionTemplate);现在你可以调用SomeClass#exe(),但我不确定这对你有什么作用。你究竟想要测试什么? - Bryan Irace
第一次调用:Reserve reserveInfo = newTransactionTemplate.execute(new TransactionCallback<Reserve>() { @Override public Reserve doInTransaction(TransactionStatus status) { return reserveService.callReserve(reserveDetails); } });第二次调用:Release releaseInfo = newTransactionTemplate.execute(new TransactionCallback<Release>() { @Override public Release doInTransaction(TransactionStatus status) { return reserveService.callRelease(id); } }); - Anj
我不明白你想要测试什么 - 如果你告诉我,我可以尝试帮助你。你想要测试哪个方法,以及你想要验证的断言是什么? - Bryan Irace
我基本上是在尝试测试SomeClass类的exe()方法。代码中有一些场景是基于reserveService.callReserve和reserveService.CallRelease的返回对象,因此我想模拟它,因为我只关心这两个调用的返回对象。 - Anj
显示剩余10条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接