当前位置: 首页 > 知识库问答 >
问题:

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

姚建树
2023-03-14

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

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

和测试:

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

注释行不工作。日志:需要但未调用: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.NativeMethodAccessorInvoke0(原生方法)在Sun.Reflect.NativeMethodAccessorInvoke(NativeMethodAccessorInvoke:39)在Sun.Reflect.DelegatingMethodAccessorInvoke(NativeMethodAccessorInvoke:25)在nit.runners.ParentRunner$1。Schedule(ParentRunner.Java:52)在org.junit.runners.ParentRunner.Runchildre(ParentRunner.Java:191)在org.junit.runners.ParentRunner.Access$000(ParentRunner.Java:42)在org.junit.runners.ParentRunner.Access$2.评估(ParentRunner.Java:184)在org.junit.runners.ParentRunner.Run(ParentRunner.Java:236)在

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

共有2个答案

曹智
2023-03-14

你不应该改变你的代码,这是对的。在单元测试中,您应该使用ArgumentCaptor捕获传递的参数,验证实例是TransactionCallback类型,并对其调用doInTransaction方法,而不是isA检查。这样您就可以验证是否使用预期的参数调用了dao(建议您可以使用eq匹配器来验证准确的值)。

这是真的,在这个测试中,你将同时测试两个东西,但这只是因为你的实现,我并不是说它是错误的。使用某些业务逻辑创建新实例总是会增加代码中的耦合,但这并不意味着我们不应该使用语言能力来实现这一点。

严宇
2023-03-14

这里的问题是测试中的transactiontemplate是一个模拟。因此,它具有与transactiontemplate相同的接口,但它不知道如何操作。您负责它的实现--这就是模拟的全部意义。您在代码中显式调用template.execute(),这就是第一次验证通过的原因。但是execute()不是来自spring的那个(或者更准确地说,您测试中的template不是spring的transactiontemplate的实例,它只是它的一个模拟)--它是,好吧,让我们假设它是“空的”,因为它是在一个模拟上调用的,并且您没有告诉模拟在它上调用execute()应该如何操作。

在这种情况下,我真的不鼓励您进行这样的单元测试,因为您在这里测试的是实现。你应该测试的,至少在我看来,是给定一定条件下的功能含义,当某件事发生时,就会出现某种结果。这将需要将其更改为集成测试(使用lets,比如DBUnit或其他任何东西),并断言是否实际删除了您应该删除的内容。我的意思是你真正关心的是什么--知道一些方法被调用了还是你希望的事情真的发生了?

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

 类似资料:
  • 我正在使用Mockito编写一个JUnit测试用例,并得到一个NullPointerException。 在我的代码中是这样的:

  • 我在我的Java,Spring Boot控制器中创建了一个函数,它允许我根据参数获得数据的和值,这很有效。然而,我很难理解用Junit和Mockito测试这个功能的最佳方式是什么?到目前为止,我已经创建了一个测试函数,它返回一个特定数组字段的值。如何能够返回。thenreturn()中的值,该值根据给定的serviceID求和?任何帮助或建议任何其他有用的帖子将被感谢,因为我无法找到任何相关的或我

  • 我有这个过滤器类,在使用junit进行测试时需要尽可能高的代码覆盖率。 和测试等级: 当我运行时,它在 线 我如何避免这种情况? 我需要调用这个方法并执行里面的任何内容来提供所需的代码覆盖。

  • 我应该如何测试异常?我可以mock connector并且我可以赋予它抛出异常的行为,但是我不明白下一步该怎么做。

  • 问题内容: 我已经开始发现Mockito库,并且有一个我没有找到正确答案的问题。 例如,如果我的UserDAO类中有将用户保存到数据库中的此类方法: 我应该如何测试? 如果我想测试一个DAO类,那么我需要创建一个模拟,模拟,模拟等吗?如此不测试数据库本身? 但是,如果我还想测试dao和数据库的行为怎么办? 您能否提供一些代码示例,可能有用的链接,并显示实现此目的的最佳方法? 问题答案: 这是使用M

  • 我对junit mockito非常陌生,并尝试使用mockito编写junit测试用例。 这是我的方法,我必须为此编写一个jUnit。 ChefService和ChefApi传递的方法参数来自第三方api 这里是呼叫chefService。listCookbookVersions()将返回CookBookVersion类类型的迭代器,如