3

I don't want to use powermock anymore. Because junit5 started mocking static classes. So i am trying to get rid of powermock methods.

As you know, you can create an instance of a class with whenNew keyword.

Is there any alternative in Junit5 for whenNew?

Here is a part of my code:

                whenNew(PDFDocument.class).withNoArguments().thenReturn(pdfDocument);
                whenNew(PSConverter.class).withNoArguments().thenReturn(converter);
                doNothing().when(pdfDocument).load(ArgumentMatchers.any(ByteArrayInputStream.class));
                doAnswer(invocationOnMock -> {
                    ByteArrayOutputStream outputStream = invocationOnMock.getArgument(1);
                    outputStream.write(content);
                    return outputStream;
                }).when(converter).convert(ArgumentMatchers.any(), ArgumentMatchers.any(ByteArrayOutputStream.class));
Emre Varol
  • 196
  • 2
  • 6
  • 18

1 Answers1

2

Mocking object construction is available since Mockito 3.5.0 according to documentation.
First of all you need add the mockito-inline instead of the mockito-core to your test dependencies.
mockito-inline provides ability to mock static or final methods, constructors. Difference between mockito-core vs mockito-inline

        <dependency>
            <groupId>org.mockito</groupId>
            <artifactId>mockito-inline</artifactId>
            <version>${mockito.version}</version>
            <scope>test</scope>
        </dependency>

Let's create a simple service for testing which instantiate objects.

public class A {
    private final String test;

    public A(String test) {
        this.test = test;
    }

    public String check() {
        return "checked " + this.test;
    }
}

public class B {
    private String check = " B check ";

    public String check() {
        return check;
    }

}

public class TestService {
    public String purchaseProduct(String param) {
        A a = new A(param);
        B b = new B();
        return a.check() + b.check();
    }
}

Example of constructor mock with comments:

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

import static org.mockito.Mockito.when;

public class ConstructorMockTest {
    @Test
    public void test_mocked_construction()  {
        try (
             //create mock for object A
             MockedConstruction<A> mockedA = Mockito.mockConstruction(A.class,
                (mock, context) -> {
                    //set return value for object A mock methods
                    when(mock.check()).thenReturn(" Constructor Mock A ");
             });
             //create mock for object B
             MockedConstruction<B> mockedB = Mockito.mockConstruction(B.class,
                     (mock, context) -> {
                         //set return value for object B mock methods
                         when(mock.check()).thenReturn(" Constructor Mock B ");
             }))
        {
            // every A object creation is current try() scope returning a mock
            A aObject = new A("test");
            Assertions.assertEquals( aObject.check(), " Constructor Mock A ");

            // every B object creation is current try() scope returning a mock
            B bObject = new B();
            Assertions.assertEquals( bObject.check(), " Constructor Mock B ");

            //Example of testing service which creates A and B objects
            TestService service = new TestService();
            String serviceResult = service.purchaseProduct("test");

            Assertions.assertEquals(serviceResult, " Constructor Mock A  Constructor Mock B ");
        }
    }
}

For your classes example:

    @Test
    public void test() {
        byte[] content = new byte[] {1,1};

        try (
                MockedConstruction<PDFDocument> mockedPDFDocument = Mockito.mockConstruction(PDFDocument.class,
                        (mock, context) -> {
                            doNothing().when(mock).load(ArgumentMatchers.any(ByteArrayInputStream.class));
                        });

                MockedConstruction<PSConverter> mockedPSConverter = Mockito.mockConstruction(PSConverter.class,
                        (mock, context) -> {
                            doAnswer(invocationOnMock -> {
                                ByteArrayOutputStream outputStream = invocationOnMock.getArgument(1);
                                outputStream.write(content);
                                return outputStream;
                            }).when(mock).convert(ArgumentMatchers.any(), ArgumentMatchers.any(ByteArrayOutputStream.class));
                        }))
        {
            //call services which instantiates PDFDocument and PSConverter
            PDFDocument pdfDocument = new PDFDocument();
            PSConverter psConverter = new PSConverter();

            Assertions.assertTrue(org.mockito.internal.util.MockUtil.isMock(pdfDocument));
            Assertions.assertTrue(org.mockito.internal.util.MockUtil.isMock(psConverter));
        }
    }
Eugene
  • 5,269
  • 2
  • 14
  • 22
  • 1
    Thank you. It works. Can you check this question too? https://stackoverflow.com/questions/72338571/spy-a-static-method-without-powermock – Emre Varol May 22 '22 at 14:42
  • You are welcome, Spy is not supported for static methods. But there is a workaround: during defining `mockStatic` you can specify which methods should return mock and which perform real execution, it can be done via invocation object `Method method = invocation.getMethod(); if ("method1".equals(method.getName())) { return invocation.getMock(); } else { return invocation.callRealMethod(); }` – Eugene May 22 '22 at 15:21
  • I will describe answer a little bit later. – Eugene May 22 '22 at 15:22
  • 1
    Okey @Eugene thank you. By the way, i mean that i want to spy a class, not an object. But this class has private constructor, and i want to test static method of this class. – Emre Varol May 22 '22 at 16:05
  • 1
    How can I use a mock object instead of defining the mock behaviour every time inside the `mockConstruction` method? For example, I have a mock object already created and I use `PowerMockito.whenNew(Foo.class).withAnyArguments().thenReturn(mockFoo);`. What is the alternative in Mockito 3.5? – Aditya Verma Nov 02 '22 at 15:45