Skippy le Grand Gourou
Skippy le Grand Gourou

Reputation: 7694

Unable to mock with Quarkus, NullPointer exception and cannot find relevant imports

I am trying to write unit tests for Quarkus using Mockito, but I fail mocking things.

Here is a minimal (not) working example :

package com.my.package;

import io.quarkus.test.junit.QuarkusTest;
import org.mockito.Mockito;
import org.mockito.Mock;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

@QuarkusTest
public class LoadCalculatorServiceTest {

    public class Foobar {
        public int baz;
        public void setBaz(int baz) {
            this.baz = baz;
        }
        public int getBaz() {
            return this.baz;
        }
    }

    @Mock
    Foobar foobar;
    // Foobar foobar = new Foobar(); // doesn’t work either

    @Test
    public void myTest() {
        Mockito.when(foobar.getBaz()).thenReturn(4); // NullPointer
        Assertions.assertEquals(4,foobar.getBaz());
    }
}

The test crashes on a NullPointer.

I read such issues may be fixed by annotating the test with @RunWith(MockitoJUnitRunner.class), @ExtendWith(MockitoExtension.class) (which for some reason I expected @QuarkusTest to do anyway ?), however I fail to find the correct imports to load them.

I tried org.junit.jupiter.api.MockitoExtension, org.junit.runner.RunWith and variations, without success.

Here is the relevant part of my pom.xml :

    <dependency>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-junit5</artifactId>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-junit5-mockito</artifactId>
      <scope>test</scope>
    </dependency>

What am I missing ?

Upvotes: 6

Views: 6859

Answers (3)

harsh pamnani
harsh pamnani

Reputation: 1756

When you are extending it with MockitoExtension, there's no necessity for the presence of @QuarkusTest. Simply include @ExtendWith(MockitoExtension.class) and exclude @QuarkusTest from your code and it should be goood.

However, if you intend to retain @QuarkusTest, you must utilize @InjectMock from Quarkus for this purpose. @InjectMock facilitates the creation of a Mockito mock. Thus, the revised code would look like below:

@QuarkusTest
public class LoadCalculatorServiceTest {
    @ApplicationScoped
    static class Foobar {
        public int baz;
        public void setBaz(int baz) {
            this.baz = baz;
        }
        public int getBaz() {
            return this.baz;
        }
    }

    @InjectMock
    Foobar foobar;

    @Test
    public void myTest() {
        when(foobar.getBaz()).thenReturn(4); 
        Assertions.assertEquals(4,foobar.getBaz());
    }
}

Upvotes: 1

Daniel Almachi
Daniel Almachi

Reputation: 33

I'm using quarkus 1.8.1.Final, with mockito 3.6.0, I had the same issue with @Mock annotation and I followed the answer from Skippy le Grand Gourou and it didn't work, so I deleted the @QuarkusTest annotation, and delete de MockitoAnnotations.initMocks(this) method, my mockito version has deprecated this, then the test run with the @Mock annotation. I'm new doing Quarkus so I don't know very well the side effects of removing @QuarkusTest

Upvotes: 0

Skippy le Grand Gourou
Skippy le Grand Gourou

Reputation: 7694

I figured the original code works with plain-style mocks :

Foobar foobar = Mockito.mock(Foobar.class);

So the question is actually how to make the @Mock annotation work ? There are several things needed for that :

  1. The @RunWith annotation has been replaced (or should we say upgraded) by @ExtendWith in JUnit5. It can be imported in Quarkus using import org.junit.jupiter.api.extension.ExtendWith;.

  2. @RunWith is usually used as @ExtendWith(MockitoExtension.class). MockitoExtension can be imported in Quarkus using import org.mockito.junit.jupiter.MockitoExtension;. Beware that the mockito-junit-jupiter dependency (from the org.mockito group) must be added to the pom.xml, since the quarkus-junit5-mockito packages do not depend on it.

  3. Mocks have to be initialized by MockitoAnnotations.initMocks() before the tests. Note that although it may seem to make more sense to use @BeforeAll for the setup function, apparently it is not the point of this annotation and one should use @BeforeEach (the former needs the setup to be static, and IIUC the setup function will be called before each test anyway).

  4. Then finally the @Mock annotation should work.

To summarize, the original code would become :

package com.my.package;

import io.quarkus.test.junit.QuarkusTest;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.junit.jupiter.MockitoExtension;

@QuarkusTest
@ExtendWith(MockitoExtension.class)
public class LoadCalculatorServiceTest {

    public class Foobar {
        public int baz;
        public void setBaz(int baz) {
            this.baz = baz;
        }
        public int getBaz() {
            return this.baz;
        }
    }

    @BeforeEach
    public void setup() {
        MockitoAnnotations.initMocks(this);
    }

    @Mock
    Foobar foobar;

    @Test
    public void myTest() {
        Mockito.when(foobar.getBaz()).thenReturn(4);
        Assertions.assertEquals(4,foobar.getBaz());
    }
}

with the following addition to the pom.xml :

<dependency>
  <groupId>org.mockito</groupId>
  <artifactId>mockito-junit-jupiter</artifactId>
  <scope>test</scope>
</dependency>

Upvotes: 7

Related Questions