Home > Net >  NotAMockException exception when trying to verify a static method with Powermockito
NotAMockException exception when trying to verify a static method with Powermockito

Time:03-14

I use PowerMock to test a static method as mentioned its documentation.

As far as I see, there may be a bug, but I am not sure:

Static mocking broken for Mockito >= 2.26.1

...

I tried the workarounds mentioned on the following pages, however it does not fix the problem and some of them cannot be applicable as they are outdated.

NotAMockException when trying to verify a static method

verifyStatic get NotAMockExcption from mockito

However, I get "Argument passed to verify() is of type Class and is not a mock!" error. Here is the service method that I am testing and test method:

service:

// I want to test this method
 public CommandDTO create(EmployeeRequest request) {
    // ...

    log();
    return CommandDTO.builder().uuid(employee.getUuid()).build();
}


private void log() {
    LoggingUtils.info("Created...");
}

test:

@RunWith(PowerMockRunner.class)
@PrepareForTest(LoggingUtils.class)
public class EMployeeServiceImplTest {

    @Test
    public void unit_test() {

        // ...

        PowerMockito.mockStatic(LoggingUtils.class);

        employeeService.create(request);

        PowerMockito.verifyStatic(LoggingUtils.class); // throws error

        LoggingUtils.info(any());
    }
}

Here are libraries and versions:

pom.xml:

<dependency>
    <groupId>org.powermock</groupId>
    <artifactId>powermock-module-junit4</artifactId>
    <version>2.0.9</version>
    <scope>test</scope>
</dependency>

<dependency>
    <groupId>org.powermock</groupId>
    <artifactId>powermock-api-mockito2</artifactId>
    <version>2.0.9</version>
    <scope>test</scope>
</dependency>

<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <version>3.4.6</version>
    <scope>test</scope>
</dependency>

CodePudding user response:

Since you asked in another comment, here's a pattern I've used in the past to prevent the need for static mocking:

Imagine we have a static method...

public class SomeClass {
  public static String doSomething(int x) { ... }
}

Now imagine our code using it like this...

public class MyClass {
  public void someMethod() {
    String xyz = SomeClass.doSomething(123);
    ...
  }
}

If we now needed to mock that SomeStaticClass.doSomething(123) call, we need static mocking.

An alternative is a delegator:

public class MyDelegator {
  public String doSomething(int x) { 
    return SomeClass.doSomething(x);
  } 
}

Now you can use that instead in your class:

public class MyClass {
  private final MyDelegator myDelegator;

  public MyClass(MyDelegator myDelegator) { this.myDelegator = myDelegator; }

  public void someMethod() {
    String xyz = myDelegator.doSomething(123);
    ...
  }
}

And voila, you can simply mock the MyDelegator object instead of having to care that the original implementation was a static call.

Of course, this doesn't solve the underlying code smell, but it can help you to work around it in cases where you cannot refactor the static code itself.

CodePudding user response:

Let me suggest a different approach altogether because I see you already use Mockito version 3.4.6 . Since Mockito >= 3.4.0 you are able to mock static methods directly. This means you can completely get rid of the PowerMock dependency.
Also, AFAIK PowerMock does not support JUnit5. This solution will allow you to upgrade your JUnit test framework to version 5 without issues which I also highly recommend.

Static mocking using Mockito does require you to use the mockito-inline dependency over mockito-core but, because mockito-inline depends on mockito-core, Maven will also download the mockito-core package. Please note that the Mockito documentation states that, at one point in the future, they might abolish this package when they pull all these "experimental" features to the core package.
Next to that, you should also replace @RunWith(PowerMockRunner.class) with @RunWith(MockitoJUnitRunner.class)

This is how you use it.

You can either define the mock per test method like so using a try-with-resources statement that automatically calls close

    try (MockedStatic<Files> filesMock = Mockito.mockStatic(Files.class)) {
        filesMock.when(() -> Files.copy(any(Path.class), any(OutputStream.class))).thenReturn(1L);
     
        // Call logic
    }

Or you can define it for all tests in a @Before method because you use jUnit4.

    private MockedStatic<Files> filesMock;

    @Before
    public void init() {
        filesMock = org.mockito.Mockito.mockStatic(Files.class);
    }

    @After
    public void teardown() {
        filesMock.close();
    }
    
    @Test
    void test() {
        filesMock.when(() -> Files.copy(any(Path.class), any(OutputStream.class))).thenReturn(1L);
    }

https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html#mockito-inline https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html#static_mocks

  • Related