【问题标题】:Branch coverage with JUnit and Mockito使用 JUnit 和 Mockito 进行分支覆盖
【发布时间】:2016-05-24 15:22:54
【问题描述】:

我正在为一个方法使用JUnit API 编写一个测试用例。我已经涵盖了所有场景,但让我感到困难的是if 块。当我将鼠标悬停在这条线上时,Cobertura 为每个条件声明 50% 50%,但我不完全确定如何解决这个问题。

待测方法:

protected boolean isDateWithinTimelineRange( Calendar date, ServiceContext ctx ) {
    Calendar end = (Calendar)ctx.getParameter( ServiceConstants.TIMELINE_END );
    Calendar start = (Calendar)ctx.getParameter( ServiceConstants.TIMELINE_BEGIN );

    if( end != null && start != null ) {
        if( date.getTimeInMillis() >= start.getTimeInMillis() && date.getTimeInMillis() <= end.getTimeInMillis() ) {
            return true;
        } else {
            return false;
        }
    }

    return true;
}

JUnit 测试用例:

@Test
public void testIsDateWithinTimelineRange() throws Exception {
    ServiceContext context = Mockito.mock(ServiceContext.class);
    Calendar calender = Mockito.mock(Calendar.class);

    Mockito.when(context.getParameter(Mockito.anyString())).thenReturn(calender);

    TestBaseTimelineProvider provider = new TestBaseTimelineProvider();
    boolean answer = provider.isDateWithinTimelineRange(calender, context);

    assertNotNull(answer);
    assertTrue(provider.isDateWithinTimelineRange(calender, context));

    // Testing for NULL condition
    context = Mockito.mock(ServiceContext.class);
    calender = Mockito.mock(Calendar.class);
    Mockito.when(context.getParameter(Mockito.anyString())).thenReturn(null);

    provider = new TestBaseTimelineProvider();
    answer = provider.isDateWithinTimelineRange(calender, context);

    assertNotNull(answer);
    assertTrue(provider.isDateWithinTimelineRange(calender, context));

    // Start date set to null
    context = Mockito.mock(ServiceContext.class);
    calender = Mockito.mock(Calendar.class);
    ServiceConstants constants = new ServiceConstants();

    Mockito.when(context.getParameter(ServiceConstants.TIMELINE_END)).thenReturn(calender);

    provider = new TestBaseTimelineProvider();
    answer = provider.isDateWithinTimelineRange(calender, context);

    assertNotNull(constants);

    // End date set to null
    context = Mockito.mock(ServiceContext.class);
    calender = Mockito.mock(Calendar.class);
    constants = new ServiceConstants();

    Mockito.when(context.getParameter(ServiceConstants.TIMELINE_BEGIN)).thenReturn(calender);

    provider = new TestBaseTimelineProvider();
    answer = provider.isDateWithinTimelineRange(calender, context);

    assertNotNull(constants);
}

让我感到困惑的是我正在模拟的参数date,它决定了endstart 变量的值。

if( date.getTimeInMillis() &gt;= start.getTimeInMillis() &amp;&amp; date.getTimeInMillis() &lt;= end.getTimeInMillis() ) {} 是我要覆盖的行。

谢谢

【问题讨论】:

  • 你不需要告诉模拟在方法getTimeInMillis() 中返回什么,例如:Mockito.when(calender.getTimeInMillis()).thenReturn(1L); 并解决这个问题吗?目前,调用date.getTimeInMillis() 不会返回任何内容,因为date 对象已被模拟,但您的getTimeInMillis() 方法没有设置任何返回
  • 您介绍了两种返回 true 的情况,但从未介绍过返回 false 的(两种)情况(第一项不为真,或第一项为真,第二项不为真)。您应该至少有一种,可能有两种情况,您 assertFalse(provider.isDateWithinTimelineRange) 对该条件进行有效测试。
  • 是的,实际上我正在调试它,所以得到了这两个相似的测试用例。我正在研究 getTimeMillis()。

标签: java junit mockito cobertura


【解决方案1】:

首先,您从未告诉您的模拟日历对象在调用getTimeInMillis() 时要做什么。您需要为每个日历条目添加以下内容:

// Assume `long desiredlong` defined;
Mockito.when(calendar.getTimeInMillis()).thenReturn(desiredlong);

您需要对 date.getTimeInMillis() 在所需范围内的一组日历对象和 date.getTimeInMillis() 在所需范围外的另一组日历对象执行此操作。

最终,涵盖该测试真实方面的案例将采用以下形式:

@Test
public void validDatesInRange() {
    ServiceContext context = Mockito.mock(ServiceContext.class);
    Calendar calenderstart = Mockito.mock(Calendar.class);
    Mockito.when(calendarstart.getTimeInMillis()).thenReturn(1L);

    Calendar calendertarget = Mockito.mock(Calendar.class);
    Mockito.when(calendartarget.getTimeInMillis()).thenReturn(2L);

    Calendar calenderend = Mockito.mock(Calendar.class);
    Mockito.when(calendarend.getTimeInMillis()).thenReturn(3L);

    Mockito.when(context.getParameter(ServiceConstants.TIMELINE_END)).thenReturn(calenderend);
    Mockito.when(context.getParameter(ServiceConstants.TIMELINE_BEGIN)).thenReturn(calenderstart);

    TestBaseTimelineProvider provider = new TestBaseTimelineProvider();
    boolean answer = provider.isDateWithinTimelineRange(calendertarget, context);

    assertNotNull(answer);
    assertTrue(provider.isDateWithinTimelineRange(calendartarget, context));
}

其次,你从来没有真正写过任何测试虚假回报的东西。要覆盖另一面,请复制上述内容,但将您的 calendartarget.getTimeInMillis() 设置为返回类似 1000L 的荒谬内容,并更改您的断言以反映错误。

您可能还希望将测试用例分解为多个方法,这些方法的名称反映了每个单独的测试方法检查的内容,例如 validDatesInRange()validDatesNotInRange()startDateIsNull()endDateIsNull()contextIsNull()。通过这样做,您的测试会变得更小,更容易理解和调试,您的测试运行会生成更清晰、信息量更大的测试报告,并且一个测试中的失败不会掩盖其他测试中的失败。

【讨论】:

  • 感谢 Brandon 的详细帖子。我一定会按照你的建议去做。
猜你喜欢
  • 1970-01-01
  • 2018-05-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-08
  • 1970-01-01
  • 1970-01-01
  • 2023-03-10
相关资源
最近更新 更多