Hot questions for Using Mockito in annotations

Question:

I am mocking a object using @Mock annotation

@Mock
Customer customer;

but the @Mock annotation is showing warning

The type MockitoAnnotations.Mock is deprecated

and my test case is failed


Answer:

You are using the wrong mock. try using the below one

org.mockito.Mock instead of org.mockito.MockitoAnnotations.Mock.

Question:

I have created an interface Client with its two concrete implementations clientA and clientB and annotated them with my custom annotation.

public interface Client{
    public void dosomething();
}

@Component
@Myannotation
public class clientA implements Client {         
    public void doSomething(){
         sysout("Client A do something");
    }
}

@Component
@Myannotation
public class clientB implements Client {         
    public void doSomething(){
       sysout("Client B do something");
    }
}

Now I am calling the overriden methods of both clientA and clientB from Alien class.

@Component
class Alien{
   @Autowired
   private ApplicationContext context;  

   public void performOperation(){
      Map<String, Object> beans = 
               context.getBeansWithAnnotation(MyAnnotation.class);
      for(Map.Entry<String, Object> entry: beans.entrySet()) {
          Client c = (Client)entry.getValue();
          c.doSomething();
      }

   }
}

I am facing problem with writing test method for performOperation.

@RunWith(MockitoJUnitRunner.class)
class AlienTest
{
   @InjectMocks
   Alien a;

   @Test
   public void testperformOperation(){
       //how to Mock for beans
       assertEquals(expected, a.performOperation());
   }
}

1) How should I write testperformOperation method(allowed to change the return type of performOperation method from void to any other type)

2) Is there any better way to get list of all implementations for Client interface without creating custom annotations.


Answer:

I would suggest you first refactoring Alien to make it more testable using Dependency Injection idea which its dependencies (i.e Client) can be injected from outside rather than hard coded inside a method which always get from the spring context:

@Component
public class Alien{

  private List<Client> clients = new ArrayList<>();

  @Autowired
  public Alien(List<Client> clients) {
        this.clients = clients;
   }

  public void performOperation(){
     for(Client c: clients) {
          c.doSomething();
      }
  }
}

If you simply want to inject all Client implementation to the Alien , you just need to @Autowired List<Client> into Alien which Spring will already help you to inject all the Client implementation to it out of the box. No need to create @Myannotation

Once you make the Alien 's dependencies injectable (i.e a list of client) , you can simply inject a mock to it and verify performOperation() really invoke all of Client 's doSomething():

@RunWith(MockitoJUnitRunner.class)
class AlienTest{

  @Mock
  private Client mockClientA;

  @Mock
  private Client mockClientB;

   @Test
   public void testperformOperation(){
   List<Client> clients = new ArrayList<>();
   clients.add(mockClientA);
   clients.add(mockClientB);

     Alien alien = new Alien(clients);
     alien.performOperation();  

     verify(mockClientA).doSomething();
   verify(mockClientB).doSomething();
   }
}

Question:

The task is to cause NoSuchMethodException exception when calling table.annotationType().getMethod("name").

I have following code

@Mock(answer = RETURNS_DEEP_STUBS)
private Table table;

@Test(expectedExceptions = NoSuchMethodException.class)
public void testGetSupportClassesDatabaseThrowException() throws NoSuchMethodException {
    String testPackageName = "com.usc.dbd.util.supporttable";

    MockitoAnnotations.initMocks(this);

    when(table.annotationType().getMethod("name")).thenThrow(NoSuchMethodException.class);

    SupportTables.getSupportClasses(testPackageName);
}

The test fails with NullPointerException on when... line.

testCompile("org.mockito:mockito-core:2.7.17")

Table is annotation from javax.persistence

Probably the issue is in mocking Table interface.

I'm looking for solution how to test such case.


Answer:

Two things here:

  • the NPE is strange ( will see if I can find an explanation later on )
  • even without an NPE, your test is pointless

You see, you create one mocked instance of the Table class. That you configure to react to a certain call with an exception.

Then you call a static method, without using that mocked object in any way. That simply will not do anything.

That later, static call doesn't know anything about your mocked table instance. You probably assume that your mock setup will affect any Table object. No, it will not! It only affects calls that happen on that specific object.

If you want to control any arbitrary instance of Table, created anywhere, you have way more things to do (for example you would have to look into using PowerMock or JMockit to intercept/control constructor calls).

Long story short: as written right now, your test case doesn't at all do what you wrote it for.

Question:

I have some annotation in a class such as

 public class ProductModel {
@Pattern(regexp="^(1|[1-9][0-9]*)$", message ="Quantity it should be number and greater than zero")
private String  quantity;

then in my controller

@Controller
public class Product Controller
private ProductService productService;
@PostMapping("/admin/product")
public String createProduct(@Valid @ModelAttribute("product") ProductModel productModel, BindingResult result)
{
    // add println for see the errors
    System.out.println("binding result: " + result);

    if (!result.hasErrors()) {
        productService.createProduct(productModel);
        return "redirect:/admin/products";
    } else {
        return "product";
    }
}

Then I am trying to do a test of createProduct from ProductController.

@RunWith(MockitoJUnitRunner.class)
public class ProductControllerTest {

@Autowired
private MockMvc mockMvc;

@Mock
ProductService productService;

@InjectMocks
ProductController productController;

@Mock
private BindingResult mockBindingResult;

@Before
public void setupTest() {
    MockitoAnnotations.initMocks(this);
    Mockito.when(mockBindingResult.hasErrors()).thenReturn(false);
}


@Test
public void  createProduct() throws Exception {

    productController = new ProductController(productService);      
   productController.createProduct(new ProductModel(), mockBindingResult);

Here I do not know how can I add values to the object productmodel and also how can I test the message output of "...number should be greater than zero". What I was trying to do it was create an object and then assert with values for making it fail or work such as assertEquals(hello,objectCreated.getName()); Any advice or help will be highly appreciated.


Answer:

To validate bean annotations you must have the context in execution. You can do this with:

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT)

Then your tests will validate the annotations.

However, if you just want to validate the annotation of model (without another business rules) you can use a validator:

private static ValidatorFactory validatorFactory;
private static Validator validator;

@BeforeClass
public static void createValidator() {
    validatorFactory = Validation.buildDefaultValidatorFactory();
    validator = validatorFactory.getValidator();
}

@AfterClass
public static void close() {
    validatorFactory.close();
}

@Test
public void shouldReturnViolation() {
    ProductModel productModel = new ProductModel();
    productModel.setQuantity("a crazy String");

    Set<ConstraintViolation<ProductModel>> violations = validator.validate(productModel);

    assertFalse(violations.isEmpty());
}

Question:

I'm trying to integrate JUnit 5 under Eclipse Oxygen3. The project already has Mockito 2.

I have done all steps suggested in https://www.baeldung.com/mockito-junit-5-extension like so:

Dependencies:

  • junit-jupiter-engine 5.5.0
  • junit-jupiter-api 5.5.0
  • junit-vintage-engine 5.5.0
  • junit-platform-runner 1.5.0
  • mockito-core 2.28.2
  • mockito-junit-jupiter 2.28.2

Code:

public class Jupiter {

    public boolean isAlpha() {
        return true;
    }

}

Test Code:

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.given; 
import java.util.Date;  
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.platform.runner.JUnitPlatform;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

@ExtendWith(MockitoExtension.class)
@RunWith(JUnitPlatform.class)
public class JupiterTest {

    @InjectMocks
    private Jupiter jupiter;

    @BeforeEach
    public void setup() {
        //usually some stuff here
    }

    @Test
    @DisplayName("heading jupiter - make it so")
    public void test() {
        boolean result = jupiter.isAlpha();

        assertThat(result).isTrue();
    }
}

Unfortunately, running tests fail.

Have anyone stumbled upon a similar problem? Is it something general or my project specific problem?

java.lang.NoSuchMethodError: org.junit.platform.commons.support.AnnotationSupport.findAnnotation(Ljava/util/Optional;Ljava/lang/Class;)Ljava/util/Optional;
    at org.mockito.junit.jupiter.MockitoExtension.retrieveAnnotationFromTestClasses(MockitoExtension.java:178)
    at org.mockito.junit.jupiter.MockitoExtension.beforeEach(MockitoExtension.java:160)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$null$0(TestMethodTestDescriptor.java:126)
...
Suppressed: java.lang.NullPointerException
    at org.mockito.junit.jupiter.MockitoExtension.afterEach(MockitoExtension.java:214)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$null$11(TestMethodTestDescriptor.java:214)
    at org.junit.jupiter.engine.execution.ThrowableCollector.execute(ThrowableCollector.java:40)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeAllAfterMethodsOrCallbacks$13(TestMethodTestDescriptor.java:226)
    at java.util.ArrayList.forEach(ArrayList.java:1257)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeAllAfterMethodsOrCallbacks(TestMethodTestDescriptor.java:224)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeAfterEachCallbacks(TestMethodTestDescriptor.java:213)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:116)
    ... 43 more

Answer:

Not sure why need all that vintage and platform stuff.. Your tests are org.junit.jupiter.api.Test;

I would do this:

1) Remove all the annotations from the class level

2) Init Mockito:

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

3) These deps should be sufficient:

junit-jupiter 5.5.0
mockito-core 2.28.2

Question:

I am using AndroidAnnotations in my project and I want to test a presenter.

The test suite runs and @Test methods are apparently called before the injection has finished, because I get NullPointerException whenever I try to use the `LoginPresenter in my test code.

@RunWith(MockitoJUnitRunner.class)
@EBean
public class LoginPresenterTest {

    @Bean
    LoginPresenter loginPresenter;

    @Mock
    private LoginView loginView;

    @AfterInject
    void initLoginPresenter() {
        loginPresenter.setLoginView(loginView);
    }

    @Test
    public void whenUserNameIsEmptyShowErrorOnLoginClicked() throws Exception {
        when(loginView.getUserName()).thenReturn("");
        when(loginView.getPassword()).thenReturn("asdasd");
        loginPresenter.onLoginClicked();
        verify(loginView).setEmailFieldErrorMessage();
    }
}

Answer:

AndroidAnnotations works by creating subclasses of the annotated classes, and adds boilerplate code in them. Then when you use your annotated classes, you will swap the generated classes in either implicitly (by injecting) or explicitly (by accessing a generated class, for example starting an annotated Activity).

So in this case to make it work, you should have run the annotation processing on the test class LoginPresenterTest, and run the test only on the generated LoginPresenterTest_ class. This can be done, but i suggest a cleaner way:

@RunWith(MockitoJUnitRunner.class)
public class LoginPresenterTest {

    private LoginPresenter loginPresenter;

    @Mock
    private LoginView loginView;

    @Before
    void setUp() {
        // mock or create a Context object
        loginPresenter = LoginPresenter_.getInstance_(context);
    }

    @Test
    public void whenUserNameIsEmptyShowErrorOnLoginClicked() throws Exception {
        when(loginView.getUserName()).thenReturn("");
        when(loginView.getPassword()).thenReturn("asdasd");
        loginPresenter.onLoginClicked();
        verify(loginView).setEmailFieldErrorMessage();
    }
}

So you have a normal test class, and you instantiate the generated bean by calling the generated factory method.

Question:

I'm writing a unit test for CatalogFacade class; the class is like this:

public class CatalogFacade{
    @Inject
    @Shallow //custom annotation
    private ITServiceMapper servMapper;
    @Inject
    @Complete //custom annotation
    private ITServiceMapper dServMapper;

    @Override
    public ITService getITService(String serviceCode) {

        ITService a = dServMapper.method();
        return a;
    }

}

and I have written the unit test in this way:

@RunWith(MockitoJUnitRunner.class)
public class CatalogFacadeTest {

    @InjectMocks
    private CatalogFacade facade;
    @Mock
    private ITServiceMapper servMapperMock;
    @Mock
    private ITServiceMapper dServMapperMock;

    @Test
    public void getITService() {
        /* prepare value objects */
        ITService dtoMock= Mockito.mock(ITService.class);

        /* Given some preconditions (Arrange) */
        given(dServMapperMock.modelToDto(entityMock)).willReturn(dtoMock);

        /* When an action occurs (Act) */
        ITService service= facade.getITService("AMS-SA-0001");

        /* Then verify the output (Assert) */
        assertThat(dtoMock.getItServiceCode(),
        is(equalTo(service.getItServiceCode())));
    }
}

but the test throws a NullPointeException because when dServMapperMock.method() is called, dservMapperMock is null, so I think it's not mocked correctly...

I think the problem could be the class ITServiceMapper has custom annotation and I'm not able to mock it.

How can I mock this class?

Thank you!


Answer:

Primary reason this isn't working is because you have more than one instance of ITServiceMapper in your class(CatalogFacade).

Mockito(specifically @InjectMocks) has some issues in these scenarios. Easiest way to fix this is by assisting Mockito with the name attribute like this

@Mock(name = "servMapper")
private ITServiceMapper servMapper;

@Mock(name = "dServMapper")
private ITServiceMapper dServMapperMock;

This is one of the reason why Constructor injection is always better than Field injection. Check this article for more info

Question:

I am using mockito to test a controller. That controller uses a repository that connects to database. I want to mock userRepository and inject it in usercontroller, but when I run the test a NullPointerException is thrown at when(userRepository.addUser(anyString(), anyString())).thenReturn(true); in the test. Also when I removed this line to see whether mockMvc also gives this error and indeed it did just that.

Thus I think the problem causer is the MockitoAnnotations.initMocks(this); that it somehow doesn't enable the annotations.

I did some research about why this is happening on Google but none of the solutions solved this problem and I don't know why this is not working.

My Controller that I want to test:

@RestController
public class UserController {

    @Autowired
    private transient userRepository userRepository;

    @PostMapping("/user/add")
    public ResponseEntity<?> addUser(@RequestBody User user) {
        String firstname = user.getUsername();
        String lastname = user.getLastName();

        boolean added = userRepository.addUser(firstname , lastname );

        if(added){
            return new ResponseEntity<>(true, HttpStatus.OK);
        }

        return new ResponseEntity<>(HttpStatus.CONFLICT);
    }

My test so far:

@RunWith(SpringRunner.class)
class UserControllerTest {

    private MockMvc mockMvc;

    @MockBean
    private UserRepository userRepository;

    @InjectMocks
    private UserController userController;

    @BeforeEach
    public void init() {
        MockitoAnnotations.initMocks(this);
        mockMvc = MockMvcBuilders
                .standaloneSetup(userController)
                .build();
    }

    @Test
    void testAddUserToDb() throws Exception {
        User user = new User();
        User.setFirstName("first");
        User.setLastName("last");

        Gson gson = new Gson();
        String request = gson.toJson(user);

        //HERE I GET NULLPOINTEREXCEPTION
        when(userRepository.addUser(anyString(), anyString())).thenReturn(true);

        mockMvc.perform(post("user/add")
                .contentType(MediaType.APPLICATION_JSON).content(request))
                .andExpect(status().isOk())
                .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8));


        verify(userRepository, times(1)).addUser(anyString(), anyString());
        verifyNoMoreInteractions(userRepository);
    }

My user repository:

@Repository
public class UserRepository {

    @Autowired
    private transient JdbcTemplate jdbcTemplate;

    public boolean addUser(String firstName, String lastName){
        boolean added = false;

        String ADD_USER = "INSERT INTO Users(firstName, lastname) VALUES(?, ?)";

        //execute sql query and retrieve result set
        int rowsHit = jdbcTemplate.update(ADD_USER, firstName, lastName);

        if (rowsHit == 1) {
            added = true;
        }

        return added;
    }

ERROR MESSAGE:

java.lang.NullPointerException
    at server.controller.UserControllerTest.testAddUserToDb(UserControllerTest.java:21)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:567)
    at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:436)
    at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:115)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$6(TestMethodTestDescriptor.java:170)
    at org.junit.jupiter.engine.execution.ThrowableCollector.execute(ThrowableCollector.java:40)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:166)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:113)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:58)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.lambda$executeRecursively$3(HierarchicalTestExecutor.java:112)
    at org.junit.platform.engine.support.hierarchical.SingleTestExecutor.executeSafely(SingleTestExecutor.java:66)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.executeRecursively(HierarchicalTestExecutor.java:108)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.execute(HierarchicalTestExecutor.java:79)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.lambda$executeRecursively$2(HierarchicalTestExecutor.java:120)
    at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183)
    at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:177)
    at java.base/java.util.Iterator.forEachRemaining(Iterator.java:133)
    at java.base/java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1801)
    at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
    at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
    at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150)
    at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173)
    at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
    at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:497)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.lambda$executeRecursively$3(HierarchicalTestExecutor.java:120)
    at org.junit.platform.engine.support.hierarchical.SingleTestExecutor.executeSafely(SingleTestExecutor.java:66)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.executeRecursively(HierarchicalTestExecutor.java:108)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.execute(HierarchicalTestExecutor.java:79)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.lambda$executeRecursively$2(HierarchicalTestExecutor.java:120)
    at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183)
    at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:177)
    at java.base/java.util.Iterator.forEachRemaining(Iterator.java:133)
    at java.base/java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1801)
    at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
    at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
    at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150)
    at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173)
    at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
    at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:497)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.lambda$executeRecursively$3(HierarchicalTestExecutor.java:120)
    at org.junit.platform.engine.support.hierarchical.SingleTestExecutor.executeSafely(SingleTestExecutor.java:66)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.executeRecursively(HierarchicalTestExecutor.java:108)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.execute(HierarchicalTestExecutor.java:79)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:55)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:43)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:220)
    at org.junit.platform.launcher.core.DefaultLauncher.lambda$execute$6(DefaultLauncher.java:188)
    at org.junit.platform.launcher.core.DefaultLauncher.withInterceptedStreams(DefaultLauncher.java:202)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:181)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:128)
    at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.processAllTestClasses(JUnitPlatformTestClassProcessor.java:102)
    at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.access$000(JUnitPlatformTestClassProcessor.java:82)
    at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor.stop(JUnitPlatformTestClassProcessor.java:78)
    at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.stop(SuiteTestClassProcessor.java:61)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:567)
    at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
    at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
    at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
    at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:94)
    at com.sun.proxy.$Proxy5.stop(Unknown Source)
    at org.gradle.api.internal.tasks.testing.worker.TestWorker.stop(TestWorker.java:132)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:567)
    at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
    at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
    at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:182)
    at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:164)
    at org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:412)
    at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
    at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
    at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:56)
    at java.base/java.lang.Thread.run(Thread.java:835)

Answer:

Edit your test class to the code below and it should not throw any NullPointerException anymore (though you have some other compile-time errors in your code, like in the controller mixing firstname with username).

@SpringBootTest
@AutoConfigureMockMvc
@RunWith(SpringRunner.class)
public class UserControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @Mock
    private UserRepository userRepository;

    @Test
    public void testAddUserToDb() throws Exception {
        User user = new User();
        user.setFirstName("first");
        user.setLastName("last");

        Gson gson = new Gson();
        String request = gson.toJson(user);

        //HERE I GET NULLPOINTEREXCEPTION
        when(userRepository.addUser(anyString(), anyString())).thenReturn(true);

        mockMvc.perform(post("user/add")
                .contentType(MediaType.APPLICATION_JSON).content(request))
                .andExpect(status().isOk())
                .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8));


        verify(userRepository, times(1)).addUser(anyString(), anyString());
        verifyNoMoreInteractions(userRepository);
    }
}

In your gradle file you are mixing Spring (Boot) versions and some other, transient dependencies of Spring. Could you also update your Gradle file to this:

plugins {
    id 'org.springframework.boot' version '2.2.1.RELEASE'
    id 'io.spring.dependency-management' version '1.0.8.RELEASE'
    id 'java'
}

sourceCompatibility = 12

repositories {
    mavenCentral()
    jcenter()
}

test {
    useJUnitPlatform()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-jdbc'
    implementation 'org.springframework.boot:spring-boot-starter-security'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    implementation group: 'com.google.code.gson', name: 'gson', version: '2.8.5'

    components {
        withModule('org.springframework:spring-beans') {
            allVariants {
                withDependencyConstraints {
                    it.findAll { it.name == 'snakeyaml' }.each { it.version { strictly '1.19' } }
                }
            }
        }
    }
}

bootJar {
    mainClassName = 'server.Application'
}

If you'll get Exceptions complaining about a datasource, then remove implementation 'org.springframework.boot:spring-boot-starter-jdbc' from the Gradle configuration (or import a datasource dependency and configure it in Gradle, if you are using a database).

Question:

I know there is an indirect answer to that question in other posts here on stackoverflow. For example this:

link

But I would need the most simple and direct answer to my particular question. Since one thing is still not entirely clear to me. I will give details below.

I am going to use an example from a book of Tomasz Kaczanowski - "Practical Unit testing with JUnit and Mockito"

The example is as follows:

Class to be tested:

public class Messenger {

    private TemplateEngine templateEngine;

    private MailServer mailServer;

    public Messenger(MailServer mailServer, TemplateEngine templateEngine) {
        this.mailServer = mailServer;
        this.templateEngine = templateEngine;
    }

    public void sendMessage(Client client, Template template) {

        String msgContent = templateEngine.prepareMessage(template, client);

        mailServer.send(client.getEmail(), msgContent);
    }
}

Test class:

public class MessengerTest {

    private static final String CLIENT_EMAIL = "some@email.com";
    private static final String MSG_CONTENT = "Dear John! You are fired.";

    @Test
    public void shouldSendEmail() {

    Template template = mock(Template.class);
    Client client = mock(Client.class);
    MailServer mailServer = mock(MailServer.class);
    TemplateEngine templateEngine = mock(TemplateEngine.class);

    Messenger sut = new Messenger(mailServer, templateEngine);

    when(client.getEmail()).thenReturn(CLIENT_EMAIL);
    when(templateEngine.prepareMessage(template, client)).thenReturn(MSG_CONTENT);

    sut.sendMessage(client, template);

    verify(mailServer).send(CLIENT_EMAIL, MSG_CONTENT);
    }
}

(I tried to format the code and make the sytnax highlited, but I don't know how to do it, even though I read some posts on meta.stackoverflow. Would appreciate hints on that as well.)

So my question is: Is the code below with annotations equivalent?

public class MessengerTest {

    private static final String CLIENT_EMAIL = "some@email.com";
    private static final String MSG_CONTENT = "Dear John! You are fired.";

    @Test
    public void shouldSendEmail() {

    @Mock
    Template template;

    @Mock
    Client client;

    @Mock
    MailServer mailServer;

    @Mock
    TemplateEngine templateEngine;

    @InjectMocks
    Messenger sut;

    // given
    when(client.getEmail()).thenReturn(CLIENT_EMAIL);
    when(templateEngine.prepareMessage(template, client)).thenReturn(MSG_CONTENT);

    // when
    sut.sendMessage(client, template);

    // then
    verify(mailServer).send(CLIENT_EMAIL, MSG_CONTENT);
    }
}

Are the comments

// given 
// when 
// then 

used properly, as good practice says?

Also, in the mentioned similar question it says, that if I want to use annotations, I need to annotate my test class with: @RunWith(MockitoJUnitRunner.class)

So it is done in the question mentioned. But in my production code I am reading, there is no such annotation, and the tests work. How come? Is that annotation necessary, or not?


Answer:

The comments are well placed, but the code is wrong, I don't even think it compiles. This code would work :

@RunWith(MockitoJUnitRunner.class)
public class MessengerTest {

    private static final String CLIENT_EMAIL = "some@email.com";
    private static final String MSG_CONTENT = "Dear John! You are fired.";

    @Mock Template template;
    @Mock Client client;
    @Mock MailServer mailServer;
    @Mock TemplateEngine templateEngine;

    @InjectMocks Messenger sut;

    @Test
    public void shouldSendEmail() {
        // given
        when(client.getEmail()).thenReturn(CLIENT_EMAIL);
        when(templateEngine.prepareMessage(template, client)).thenReturn(MSG_CONTENT);

        // when
        sut.sendMessage(client, template);

        // then
        verify(mailServer).send(CLIENT_EMAIL, MSG_CONTENT);
    }
}

Don't forget the the runner (as shown in the above snippet), or a mockito rule (available only in the latests releases).

Also, in the mentioned similar question it says, that if I want to use annotations, I need to annotate my test class with: @RunWith(MockitoJUnitRunner.class)

Another possibility to make the test work is to have an test init method like that :

@Before public void init_mocks() { MockitoAnnotations.initMocks(this); }