如何使用JUnit或Mockito测试匿名方法?

Dmi*_*voi 8 java junit mockito

我有简单的类,但有匿名代码块.我需要用测试来覆盖这个课程.

public class CleanerTask {

    private final Logger log = LoggerFactory.getLogger(getClass());
    DataWarehouseMessageDao dwMessageDao;
    int cleanerDelay = 0;
    TransactionTemplate template;

    public CleanerTask(DataWarehouseMessageDao dwMessageDao, int cleanerDelay, TransactionTemplate template) {
        this.dwMessageDao = dwMessageDao;
        this.cleanerDelay = cleanerDelay;
        this.template = template;
    }

    public void clean() {
        log.info("Cleaner started");
        final Date olderThan = new Date();
        olderThan.setDate(olderThan.getDate() + cleanerDelay);
        template.execute(new TransactionCallback<Date>() {
            @Override
            public Date doInTransaction(TransactionStatus transactionStatus) {
                dwMessageDao.deleteAllByStatusAndDate(DataWarehouseMessageStatus.SAVED.getValue(), olderThan);
                return olderThan;
            }
        });
    }
}
Run Code Online (Sandbox Code Playgroud)

并测试:

@RunWith(MockitoJUnitRunner.class)
public class CleanerTaskTest {

    final static int CLEANER_DELAY = 5;

    @Mock
    DataWarehouseMessageDao dao;

    @Mock
    TransactionTemplate template;

    CleanerTask cleanerTask;

    @Before
    public void setUp() throws Exception {
        cleanerTask = new CleanerTask(dao, CLEANER_DELAY, template);
    }

    @Test
    public void successfulScenario() {
        try {
            cleanerTask.clean();
            verify(template, times(1)).execute(isA(TransactionCallback.class));
            //that verify was not triggered    
            //verify(dao, times(1)).deleteAllByStatusAndDate(anyInt(), isA(Date.class));
        } catch (Exception e) {
            e.printStackTrace();
            fail("No exceptions must occur");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

注释行不起作用.日志:通缉但未调用:dao.deleteAllByStatusAndDate(,isA(java.util.Date)); - >在com.nxsystems.dw.publisher.handler.CleanerTaskTest.successfulScenario(CleanerTaskTest.java:52)实际上,与这个模拟没有交互.

在com.nxsystems.dw.publisher.handler.CleanerTaskTest.successfulScenario(CleanerTaskTest.java:52)在sun.reflect.NativeMethodAccessorImpl.invoke0(本机方法)在sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)在阳光下.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)在org.junit.runners.model.FrameworkMethod $ 1.runReflectiveCall(FrameworkMethod.java:44)在org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable. java:15)org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)at org.junit.internal .runners.statements.RunBefores.evaluate(RunBefores.java:28)在org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:76)在org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)在org.ju上的org.junit.runners.ParentRunner $ 3.run(ParentRunner.java:193)nit.runners.ParentRunner $ 1.schedule(ParentRunner.java:52)在org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)在org.junit.runners.ParentRunner.access $ 000(ParentRunner.java:42)在在org.junit.runners.ParentRunner.run(ParentRunner.java:236)在org.mockito.internal.runners.JUnit45AndHigherRunnerImpl.run(JUnit45AndHigherRunnerImpl org.junit.runners.ParentRunner $ 2.evaluate(ParentRunner.java:184).的java:37)在org.mockito.runners.MockitoJUnitRunner.run(MockitoJUnitRunner.java:62)在org.junit.runner.JUnitCore.run(JUnitCore.java:157)在com.intellij.rt.execution.junit.JUnitStarter .主要(JUnitStarter.java:62)

此时,当启动此tets时,调试器不会进入匿名块.那么如何让Mockito进入匿名区?

Mat*_*zyk 12

为什么它不起作用

那么你的问题是TransactionTemplate在你的测试中是一个模拟.因此它具有相同的界面,TransactionTemplate但它不知道如何表现.你负责实施 - 这就是模拟的全部要点.您明确地调用template.execute()了代码,这就是您的第一次验证通过的原因.但这execute()不是来自Spring的那个(或者更确切地说,template在你的测试中不是Spring的实例TransactionTemplate,它只是对它的嘲弄) - 它是,好吧,让它说是"空",因为它是在模拟上调用的你没有告诉模拟如何调用execute()它应该表现.

我该如何解决它

在这种情况下,我真的不鼓励你进行这样的单元测试,因为你在这里测试实现.你应该考什么,至少根据我的,是功能意义给予一定的条件下,有事情发生那么应该发生了一些成绩.这需要将其更改为集成测试(使用假设DBUnit或其他任何东西)并声明您是否实际删除了应该删除的内容.我的意思是你真正关心的是什么 - 知道某些方法被调用或者你希望实际发生的事情?

你怎么可以,但恕我直言不应该,修复它.

但是如果你真的想要测试那段匿名代码,那么我只需将它(整个匿名类)提取到一个单独的类中,并为该新类编写一个单元测试,更准确地说是为它的doInTransaction()方法.在这种情况下,你可以使用它来创建它new,DataWarehouseMessageDao在其中设置一个模拟并简单地做你的verify().