0

I'm running a basic Spring App with Mockito 3.1.0 and and Junit 5.5.2. I have a Service call that includes two Spring Data JPA repositories. These are passed into the constructor for DI (along with two others that are immaterial – I'm including them in case they could also, potentially, cause errors.) I see no issues with the service when the app runs.

When I run my test, I get a NPE for myService. Stepping through the stack trace, hasn't really shown me anything that relates to the error. I have also tried (following this Article: https://www.baeldung.com/mockito-junit-5-extension) updating my test class to look like this:

@ExtendWith(MockitoExtension.class)
@RunWith(JUnitPlatform.class) // This dependency doesn't seem to exist
public class MyServiceTest {
    // ...

    @BeforeEach 
    // not the JUnit4 @Before annotation.
    // Interestingly, this gives me NPEs for the repositories, not the service.
    public void setup(){
        // ...
    }
}

to no avail. What I suspect is happening is that something about my setup isn't properly wired up – either as dependencies or syntax for DI.

How do I debug this? What am I missing? Thanks in advance!

Service:

import org.springframework.stereotype.Service;

@Service
public class MyService {
    private final Repository1 repository1;
    private final Repository2 repository2;
    private final Repository3 repository3;
    private final Repository4 repository4;

  public MyService(Repository1 repository1,
      Repository2 repository2,
      Repository3 repository3,
      Repository4 repository4) {
    this.repository1 = repository1;
    this.repository2 = repository2;
    this.repository3 = repository3;
    this.repository4 = repository4;
  }

    public Boolean computeValue(String someInput) {
        // does computations with repository1, repository2.
    }
}

Test:

import static org.mockito.Mockito.when;
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;

@RunWith(MockitoJUnitRunner.class)
public class MyServiceTest {

    @Mock
    private Repository1 repository1;

    @Mock
    private Repository2 repository2;

    @Mock
    private Repository3 repository3;

    @Mock
    private Repository4 repository4;

    @InjectMocks
    private MyService myService;

    @Before
    public void setup {
        when(repository1.findAll()).thenReturn(new ArrayList<>());
        when(repository1.findAllByInput(anyString())).thenReturn(new ArrayList<>());
        // Yes; I'm aware that this could also be a call to
        // MockitoAnnotations.initMocks(this). I've tried it:
        // it doesn't work. Also, I've intentionally not taken this
        // approach due to reasons:
        //   - https://stackoverflow.com/questions/10806345/runwithmockitojunitrunner-class-vs-mockitoannotations-initmocksthis
    }

    @Test
  void callMyService() {
        assertTrue(myService.computeValue("123"));
    }
}

Sample Repository:

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

// This is just an example, but this pattern is repeated against all
// repositories in the project.
@Repository
public interface Repository1 extends JpaRepository<Repository1, String> {
}

Edit:

  • I forgot to mention that I have other files in this project that are using exactly these annotations (@RunWith(MockitoJUnitRunner.class), @Mock, @InjectMocks, @Before) that are not failing.
  • I updated the files with the relevant imports, and added an example of RepositoryN.
  • I update the MyService class to better reflect the parameters.
b_archer
  • 317
  • 3
  • 11
  • 1
    Something is off here. Your code should work. Can you please add the complete `MyService` and `MyServiceTest` code please? Thanks – João Dias Nov 03 '21 at 17:30
  • 1
    Please show us the imports (ideally separately for the jUnit 4 and jUnit 5 version). – Lesiak Nov 03 '21 at 17:51
  • Thanks João and Lesiak for the feedback. I've added the relevant imports and verified the examples above. Please LMK if you have any questions. – b_archer Nov 03 '21 at 18:37
  • Can you please include the complete `MyService` code? The constructor seems odd. – João Dias Nov 03 '21 at 18:39
  • I fixed the constructor's code (sorry about that.) – b_archer Nov 03 '21 at 18:45
  • 1
    So you run a test with mockito, no Spring used for running the test and you wonder why Spring isn't injecting dependencies? Your test is for Mockito, but you are using Junit4 to run a junit5 test, that isn't going to work. Ditch `@RunWith` and use `@ExtendsWith` from JUnit5. – M. Deinum Nov 03 '21 at 18:46
  • > So you run a test with mockito, no Spring used for running the test and you wonder why Spring isn't injecting dependencies? I'm following the project's conventions. These conventions do appear to be working for other test suites in the project, just not for this one. To be clear, I'm not opposed to _changing_ how the passing tests are structured, but doing so doesn't explain why the failing tests are not working or why dependencies are not injected. – b_archer Nov 03 '21 at 19:04

3 Answers3

2

For anybody else who encounters this in the future, we were able to fix this problem by changing one of the imports from:

import org.junit.jupiter.api.Test;

to

import org.junit.Test;

Edit:

  • This had to do with differing versions of JUnit. There's a good long-form explanation as to why here.
b_archer
  • 317
  • 3
  • 11
0

Seems like your object myService, is not instantiated. I would suggest not use @InjectMocks and directly create your object as your repositories are already instantiated. MyService myService = new MyService(..., ..., ...)

Harry Coder
  • 2,429
  • 2
  • 28
  • 32
  • Thanks Harry – when I do this, interestingly, the `myService` instance now contains a bunch of `null` repositories. This could indicate that the DI component `@InjectMocks` or direct constructor DI is not the root cause. – b_archer Nov 03 '21 at 17:23
  • As you are mocking your repositories they should not be null. Maybe you a `Mockito` initialisation issue. In `JUnit 5` you use `@ExtendWith(MockitoExtension.class)`. Can you display your `pom.xml` file? – Harry Coder Nov 03 '21 at 19:02
0

I suppose you have to annotate your test class with @ExtendWith(SpringExtension.class) and not with MockitoExtension.class

More info here Junit 5 with Spring Boot: When to use @ExtendWith Spring or Mockito?

Luca Farsetti
  • 257
  • 2
  • 14
  • Thanks Luca. I added an edit to show that I have other files in this project that are using the `@RunWith(MockitoJUnitRunner.class)` annotation and passing. I'll post the rest of the imports shortly. – b_archer Nov 03 '21 at 18:18
  • just noted that in your repository declaration you have as first generic value `Repository1`. It is a typo? – Luca Farsetti Nov 04 '21 at 07:48