Hot questions for Using Mockito in cobertura

Question:

Greetings for the intelligent folks,

I am using cobertura along with mockito & powermocktio to get the code coverage. I have 1.7 java version in my machine installed.

When I run the junit test cases in eclipse,all the test cases are getting passed. But when I run ,

mvn cobertura:cobertura

I am getting following error.

java.lang.ClassFormatError: Invalid method Code length 75567 in class file

I researched and came to know that this is because of the memory size allocated for a metod by JVM.

My test class is referring a legacy class that has a static method which is very huge .I cannot go and touch the legacy or main class for refractoring because of so many impacts .

Any ideas to get rid of this exception without touching the main class would be appreciated.

Thanks Pradeep


Answer:

Simple, exclude the legacy class from Cobertura instrumentation. Something like the following, when using Maven:

<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>cobertura-maven-plugin</artifactId>
    <version>2.6</version>
    <configuration>
        <instrumentation>
            <excludes>
                <exclude>aaa/**/Legacy.class</exclude>
            </excludes>
        </instrumentation>
    </configuration>
</plugin>

Question:

I am writing a test case using JUnit API for a method. I've covered all the scenarios but the one that is giving me a hard time is in the if block. When I hover over this line the Cobertura states 50% 50% for each condition but I am not exactly sure how to get this covered.

Method under test:

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 case:

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

What confuses me is the parameter date that I am mocking and which determines the values for the end and startvariables.

if( date.getTimeInMillis() >= start.getTimeInMillis() && date.getTimeInMillis() <= end.getTimeInMillis() ) {} is the line that I want to cover.

Thanks


Answer:

Firstly, you never told your mocked calendar objects what to do when getTimeInMillis() is called. You need to add the following for each calendar entry:

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

You will need to do this for a set of calendar objects where the date.getTimeInMillis() is in the desired range, and another set where date.getTimeInMillis() is outside the desired range.

Ultimately, a case that covers the true side of that test would take the form:

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

Secondly, you never actually wrote anything that tests for a false return. To cover the other side, copy the above but set your calendartarget.getTimeInMillis() to return something ridiculous like 1000L and change your assertions to reflect false.

You may also wish to break your test cases into multiple methods whose names reflect what each individual test method checks for, like validDatesInRange(), validDatesNotInRange(), startDateIsNull(), endDateIsNull(), contextIsNull(). By doing so, your tests become smaller and easier to understand and debug, your test runs produce cleaner and far more informative test reports, and a failure in one test will not mask failures in others.

Question:

I am writing a JUnit to enhance the line and branch coverage of a method. There is only one line left in method under test that I am trying to cover but somehow it is not being covered. I've tried to use Mockito to make it simpler but still if( o != null ) comes as red in Cobertura Report.

Method under test:

public String handleParams( Map<String, Object> params ) {
    StringBuilder sb = new StringBuilder();

    if( params != null ) {
        Set<String> keys = params.keySet();
        for( String s : keys ) {
            Object o = params.get( s );
            if( o != null ) {
                if( sb.length() > 0 ) {
                    sb.append("," );
                }
                sb.append( s + "-" + o.toString() );
            }
        }
    }

    return sb.toString();
}

JUnit test:

@Test
public void testHandleParams() throws Exception {
    Map<String, Object> params = new HashMap<>();
    params.put("Object1", new Object());
    params.put("Object2", new Object());

    TestWSAuditHandler handler = new TestWSAuditHandler();
    String handle = handler.handleParams(params);

    assertNotNull(params);
    assertEquals(2, params.size());
    assertTrue(handle instanceof String);

    // Null Condition
    params = null;

    handler = new TestWSAuditHandler();
    handle = handler.handleParams(params);

    assertNull(params);
    assertEquals(null, params);
    assertTrue(handle instanceof String);

    // Mocking params
    params = Mockito.mock(Map.class);
    Mockito.when(params.get(Mockito.anyString())).thenReturn(null);

    handler = new TestWSAuditHandler();
    handle = handler.handleParams(params);
}

Want to know how will I make o == null

Thanks in advance


Answer:

How about:

params.put("Object3", null);

before your call to handleParams?

This way, when you will call params.get("Object3") in handleParams, you will get the value associated to the key Object3, which in this case is null.