简体   繁体   English

如何使用 mockito 在匿名 class 中测试方法调用

[英]How to test a method invocation inside an anonymous class using mockito

@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");

                }
            }
        }       
    }

This is the sample code I want to test.这是我要测试的示例代码。 I couldn't find much on testing anonymous class on net.我在网上测试匿名 class 时找不到太多东西。 I want to test the exe() method, go through newTransactionTemplate.execute method and mock the call to reserveService.callReserve(reserveDetails).我想通过 newTransactionTemplate.execute 方法测试 exe() 方法 go 并模拟对 reserveService.callReserve(reserveDetails) 的调用。

Can any body please suggest how can I test this situation?任何机构都可以建议我如何测试这种情况吗?

here is the sample how i'm trying to test:这是我尝试测试的示例:

 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());

    }

The second call to when(mockTransactionTemplate.execute.. with return object releaseInfo throws java.lang.ClassCastException:第二次调用 when(mockTransactionTemplate.execute.. with return object releaseInfo 抛出 java.lang.ClassCastException:

Here is the solution to the above mentioned scenario.这是上述场景的解决方案。 As I was not interested in testing the invocation of newTransactionTemplate.execute() , it being an spring API.因为我对测试newTransactionTemplate.execute()的调用不感兴趣,所以它是 spring API。 I wanted to test the invocation of reserveService.callReserve(reserveDetails) and reserveService.callRelease(id) .我想测试reserveService.callReserve(reserveDetails)reserveService.callRelease(id)的调用。 The only way to test this is if we create a transactiontemplate/transactioncallback "real" implementation/stub that is just pass thru.测试这一点的唯一方法是,如果我们创建一个只是通过的事务模板/事务回调“真实”实现/存根。 so the doIntransaction method should do nothing more than execute the action.所以 doIntransaction 方法应该只执行操作。 then we can set expectation on the action methods which in this case is the reserveService .然后我们可以对操作方法设置期望,在这种情况下是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)); 

Where does reserveService come from? reserveService是从哪里来的? If you are injecting it through either SomeClass 's constructor or a setter, you can pass a mock instead.如果您通过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);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM