Sunday, May 4, 2014

comparing mockito and powermock

I changed job so I don't work on Selenium as much as the last project. Right now I am writing more junit tests than functional tests. I have observed this interesting behavior of some popular mocking libraries and I would like to share it with you.

I have written two tests for this class, one in Mockito, one in PowerMock,
package com.algocrafts.development;

public class Developer {

    private final SVN svn;
    private final Build build;
    private final Activities activities;

    public Developer(SVN svn, Build build, Activities activities) {
        this.svn = svn;
        this.build = build;
        this.activities = activities;
    }

    public void work() {
        activities.standupMeeting();
        activities.tdd();
        if (build.isGreen()) {
            svn.checkin();
        } else {
            activities.drinkCoffee();
        }
        activities.lunch();
        activities.tdd();
    }
}
Test in Mockito
package com.algocrafts.development;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;

import static org.mockito.Mockito.*;

@RunWith(MockitoJUnitRunner.class)
public class DeveloperMockitoTest {

    @Mock private SVN svn;
    @Mock private Build build;
    @Mock private Activities activities;

    @Test
    public void whenBuildIsGreen() {

        when(build.isGreen()).thenReturn(true);

        new Developer(svn, build, activities).work();
        verify(activities).standupMeeting();
        verify(activities, times(2)).tdd();
        verify(svn).checkin();
        verify(activities, never()).drinkCoffee();
        verify(activities).lunch();
    }

    @Test
    public void whenBuildIsNotGreen() {

        when(build.isGreen()).thenReturn(false);

        new Developer(svn, build, activities).work();
        verify(activities).standupMeeting();
        verify(activities, times(2)).tdd();
        verify(svn, never()).checkin();
        verify(activities).drinkCoffee();
        verify(activities).lunch();
    }
}
Test in PowerMock,
package com.algocrafts.development;


import org.easymock.EasyMock;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.easymock.PowerMock;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

import static org.easymock.EasyMock.expect;
import static org.powermock.api.easymock.PowerMock.expectLastCall;
import static org.powermock.api.easymock.PowerMock.replayAll;
import static org.powermock.api.easymock.PowerMock.verifyAll;

@RunWith(PowerMockRunner.class)
@PrepareForTest({Developer.class, SVN.class, Build.class, Activities.class})
public class DeveloperPowerTest {

    private SVN svn;
    private Build build;
    private Activities activities;

    @Test
    public void whenBuildIsGreen() {

        activities = PowerMock.createMock(Activities.class);
        activities.standupMeeting();
        expectLastCall();
        activities.tdd();
        expectLastCall().times(2);

        build = PowerMock.createMock(Build.class);
        expect(build.isGreen()).andReturn(true);

        svn = PowerMock.createMock(SVN.class);
        svn.checkin();
        expectLastCall();

        activities.lunch();
        expectLastCall();

        replayAll();

        new Developer(svn, build, activities).work();
        verifyAll();
    }

    @Test
    public void whenBuildIsNotGreen() {

        activities = PowerMock.createMock(Activities.class);
        activities.standupMeeting();
        expectLastCall();
        activities.tdd();
        expectLastCall().times(2);

        build = PowerMock.createMock(Build.class);
        expect(build.isGreen()).andReturn(false);

        activities.drinkCoffee();
        EasyMock.expectLastCall();

        activities.lunch();
        expectLastCall();

        replayAll();

        new Developer(svn, build, activities).work();
        verifyAll();
    }
}
You may notice that the test in Mockito is simpler, but that's not the point I am trying to make.
Now let us add one line code to the Developer class,
package com.algocrafts.development;

public class Developer {

    private final SVN svn;
    private final Build build;
    private final Activities activities;

    public Developer(SVN svn, Build build, Activities activities) {
        this.svn = svn;
        this.build = build;
        this.activities = activities;
    }

    public void work() {
        activities.standupMeeting();
        activities.tdd();
        if (build.isGreen()) {
            activities.stareAtScreenForHalfHourDoingNothing();  //This line is added by mistake.
            svn.checkin();
        } else {
            activities.drinkCoffee();
        }
        activities.lunch();
        activities.tdd();
    }
}
and run both tests, the test written in Mockito still passes but the the test written in PowerMock fails. What does this mean?

This means, in my opinion which may not matter too much, test written in PowerMock is safer than Mockito. What plays the critical role?
PowerMock.verifyAll();

No comments:

Post a Comment