1

JUnit5 does not support PowerMockRunner hence the following code will not work whenever you migrate from JUnit4 to JUnit5.

Eg. Code you trying to inject mock

import javax.naming.InvalidNameException;

public class Main {

    public static void main(String[] args) {
        Main main = new Main();
        main.publish();
    }

    public void publish() {
        try {
            Sample s = new Sample();
            s.invoke("Hello");
        } catch (InvalidNameException e) {
            throw new ServiceFailureException(e.getMessage());
        }
    }

} 

Here you are trying to test publish method where you mock the Sample instance to respond with different responses. In JUnit4 you could have use PowerMockito to achieve that.

import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

import javax.naming.InvalidNameException;

@RunWith(PowerMockRunner.class)
@PrepareForTest({Main.class})
public class MainTest {

    @Test
    public void testPublishSuccess() {
        Main m = new Main();
        Assert.assertEquals("Expected result not found", "success", m.publish());
    }

    @Test
    public void testPublishFailure() throws Exception{
        Sample sample = new Sample();
        PowerMockito.when(sample.invoke(Mockito.anyString())).thenReturn("failure");
        PowerMockito.whenNew(Sample.class).withNoArguments().thenReturn(sample);

        Main m = new Main();
        Assert.assertEquals("Expected result not found", "failure", m.publish());
    }

    @Test(expected = ServiceFailureException.class)
    public void testPublishException() throws Exception{
        Sample sample = new Sample();
        PowerMockito.when(sample.invoke(Mockito.anyString())).thenThrow(new InvalidNameException("Invalid name provided"));
        PowerMockito.whenNew(Sample.class).withNoArguments().thenReturn(sample);

        Main m = new Main();
        m.publish();
    }
}

With the introduction of JUnit5, the test cases are failing at mock creating new instances because PowerMockRunner does not support JUnit5.

What is the alternate for using PowerMockito with JUnit5.

Eranda
  • 1,439
  • 1
  • 17
  • 30

1 Answers1

2

As PowerMockito does not support JUnit5, we can use Mockito inline. Here is the code which replace the PowerMockito.

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.mockito.MockedConstruction;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;

import javax.naming.InvalidNameException;

public class MainTestJunit5 {

    @Test
    public void testPublishSuccess() {
        Main m = new Main();
        Assertions.assertEquals("success", m.publish(), "Expected result not found");
    }

    @Test
    public void testPublishFailure() throws Exception{
        try (MockedConstruction<Sample> mockedConstruction = Mockito.mockConstruction(Sample.class, (sampleMock, context) -> {
            Mockito.when(sampleMock.invoke(Mockito.anyString())).thenReturn("failure");
        })) {
            Sample sample = new Sample();
            PowerMockito.when(sample.invoke(Mockito.anyString())).thenReturn("failure");
            PowerMockito.whenNew(Sample.class).withNoArguments().thenReturn(sample);

            Main m = new Main();
            Assertions.assertEquals("Expected result not found", "failure", m.publish());
        }
    }

    @Test
    public void testPublishException() throws Exception{
        try (MockedConstruction<Sample> mockedConstruction = Mockito.mockConstruction(Sample.class, (sampleMock, context) -> {
            Mockito.when(sampleMock.invoke(Mockito.anyString())).thenThrow(new InvalidNameException("Invalid name found"));
        })){

            Main m = new Main();
            boolean error = false;
            try {
                m.publish();
            } catch (ServiceFailureException e) {
                error = true;
            }

            Assertions.assertTrue(error, "Exception throwing expected");
        }
    }
}

Couple of things you need to pay attention

  • Setting up mockito-inline need additional dependency and an additional configuration.
  • Extra test runners (PowerMockRunner) and preparation for testing is not needed.
  • MockedConstruction is scoped, so you have to put all the mocking and processing done within that code block.
  • JUnit5 messages are the final method argument.

Mockito documentation: https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html#49

Eranda
  • 1,439
  • 1
  • 17
  • 30