Hot questions for Using Mockito in properties

Question:

Say I am mocking this class Foo

class Foo {
  public void doThing(Bar bar) {
    // ...
  }
}

and this is Bar

class Bar {
  private int i;
  public int getI() { return i; }
  public void setI(int i) { this.i = i; }
}

I know I can use Mockito's verify functionality to see if Foo#doThing(Bar) was called on the mock with a specific instance of Bar or any Bar with Mockito.any(Bar.class), but is there some way to ensure it was called by any Bar but with a specific value for i or Bar#getI()?

What I know is possible:

Foo mockedFoo = mock(Foo.class);
Bar someBar = mock(Bar.class);
...
verify(mockedFoo).doThing(someBar);
verify(mockedFoo).doThing(any(Bar.class);

What I want to know is if there is a way to verify that a Bar with particular things true about it was passed as an argument.


Answer:

In Mockito 2.1.0 and up with Java 8 you can pass the lambda to argThat out of the box so that one does not need a custom argument matchers. For the example in the OP would be:

verify(mockedFoo).doThing(argThat((Bar aBar) -> aBar.getI() == 5));

This is because as of Mockito 2.1.0, ArgumentMatcher is a functional interface.

Question:

Given the following @Component class:

@Component
public class MovieFinderImpl implements MovieFinder {

    @Autowired
    private Movie movie;

    @Override
    public List<Movie> findAll() {      
        List<Movie> movies = new ArrayList<>();
        movies.add(movie);
        return movies;
    }

}

I am trying to learn how to unit test this example component without doing an integration test (so no @RunWith(SpringRunner.class) and @SpringBootTest annotations on the test class).

When my test class looks like this:

public class MovieFinderImplTest {

    @InjectMocks
    private MovieFinderImpl movieFinderImpl;

    @Mock
    public Movie movieMock;

    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);
        movieMock.setTitle("test");
        movieMock.setDirector("directorTest");
    }

    @Test
    public void testFindAll() {         
        List<Movie> movies = movieFinderImpl.findAll();
        Assert.assertNotNull(movies.get(0));

        String expectedTitle = "test";
        String actualTitle = movies.get(0).getTitle();
        Assert.assertTrue(String.format("The expected name is %s, but the actual name is %s", expectedTitle, actualTitle), expectedTitle.equals(actualTitle));

        String expectedDirector = "testDirector";
        String actualDirector = movies.get(0).getDirector();
        Assert.assertTrue(String.format("The expected name is %s, but the actual name is %s", expectedDirector, actualDirector), expectedDirector.equals(actualDirector));
    }
}

... the mock is not null, but the mock class variables are and thus:

java.lang.AssertionError: The expected name is test, but the actual name is null

I have browsed through http://www.vogella.com/tutorials/Mockito/article.html , but was unable to find an example of how to set a class variable on a mock.

How do I properly mock the movie object? More in general is this the proper way to test this MovieFinderImp class? My inspiration of just component testing was this blog https://spring.io/blog/2016/04/15/testing-improvements-in-spring-boot-1-4

(ps: I wonder if I should actually test movie.get() method in this test class...perhaps my test design is just wrong).


Answer:

There is a problem with the way you are mocking in a @Before method. Instead of

movieMock.setTitle("test");
movieMock.setDirector("directorTest");

Do it like that

Mockito.when(movieMock.getTitle()).thenReturn("test");
Mockito.when(movieMock.getDirector()).thenReturn("directorTest");

Question:

I have a project with Spring mvc and Spring boot.

This project is deployed on a JBoss server and the application.properties file is on this server.

Now I want to write a test for a spring controller. For this test, I need to use the security configuration. And in the security configuration file, I have @Value annotation to get values from the application.properties file.

Given that this file is not in the project, how can I mock it to run my test ?

Here is my test class :

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {PortalWebSecurityConfig.class})
@WebAppConfiguration
public class DashboardControllerTests {

    @Mock
    private IssueNotificationManager issueNotificationManager;

    @InjectMocks
    private DashboardController dashboardController;

    private MockMvc mockMvc;

    @Before
    public void setup() {
        MockitoAnnotations.initMocks(this);
        mockMvc = MockMvcBuilders.standaloneSetup(dashboardController).build();
    }

    @Test
    @WithMockCustomZenithUser(customUser = "LOGIN")
    public void dashboardControllerTestOk() throws Exception {

        when(issueNotificationManager.findIssueNotifications("User"))
                .thenReturn(new BusinessObjectCollection<>());

        mockMvc.perform(get("/").with(testSecurityContext()))
                .andDo(print())
                .andExpect(status().isOk())
                .andExpect(view().name("index"))
                .andExpect(model().size(4))
                .andExpect(model().attributeExists("issueNotifications"));
            verify(issueNotificationManager).findIssueNotifications("User");
    }
}

I have this error in my log file :

09:16:19.899 [main] DEBUG o.s.c.e.PropertySourcesPropertyResolver - Searching for key 'ad.domain' in [environmentProperties]
09:16:19.899 [main] DEBUG o.s.c.e.PropertySourcesPropertyResolver - Searching for key 'ad.domain' in [servletConfigInitParams]
09:16:19.899 [main] DEBUG o.s.c.e.PropertySourcesPropertyResolver - Searching for key 'ad.domain' in [servletContextInitParams]
09:16:19.900 [main] DEBUG o.s.c.e.PropertySourcesPropertyResolver - Searching for key 'ad.domain' in [systemProperties]
09:16:19.900 [main] DEBUG o.s.c.e.PropertySourcesPropertyResolver - Searching for key 'ad.domain' in [systemEnvironment]
09:16:19.900 [main] DEBUG o.s.c.e.PropertySourcesPropertyResolver - Could not find key 'ad.domain' in any property source. Returning [null]
09:16:19.900 [main] DEBUG o.s.c.e.PropertySourcesPropertyResolver - Searching for key 'ad.domain' in [localProperties]
09:16:19.900 [main] DEBUG o.s.c.e.PropertySourcesPropertyResolver - Could not find key 'ad.domain' in any property source. Returning [null]
09:16:19.903 [main] WARN  o.s.w.c.s.GenericWebApplicationContext - Exception encountered during context initialization - cancelling refresh attempt
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'portalWebSecurityConfig': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: protected java.lang.String com.geodis.rt.zenith.framework.webui.authentification.WebSecurityConfig.domain; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder 'ad.domain' in string value "${ad.domain}"

Answer:

TestPropertySource sets a location to a property file. It is even possible to inline specific values:

@TestPropertySource(properties = { "task.enabled = false" })

Question:

This is a very simplified version of my code, that illustrates the specific problem.

Is there any way that I can control what happens when accountProductRepository.refresh() is called from the test?

Somehow I need to set the ProductPojo on the AccountProductPojo created in the buyProduct() method, so I don't get a null pointer when accessing the getProduct().getName() property.

refresh uses javax.persistence.EntityManager.refresh() to load the navigation properties based on the id's set in the buyProduct() method.

public class ProductServiceTest {
    @InjectMocks
    IProductService productService = new ProductService();
    @Mock
    IWriteANoteService writeANoteService;
    @Mock
    IAccountProductRepository accountProductRepository;

    @Test
    public void buyProductTest() {
        productService.buyProduct(1l, 1l);
    }
}

@Service
public class ProductService implements IProductService {
    @Autowired
    IWriteANoteService writeANoteService;

    @Autowired
    IAccountProductRepository accountProductRepository:

    public void buyProduct(Long productId, Long accountId) {
        AccountProductPojo accountProduct = new AccountProductPojo();
        accountProduct.setProductId(productId);
        accountProduct.setAccountId(accountId);

        accountProductRepository.persist(accountProduct);
        // load navigation properties
        accountProductRepository.refresh(accountProduct);

        writeANoteService.writeAccountNote(accountId, "Bought product " + accountProduct.getProduct().getName());
    }
}

@Entity
@Table(name = "account_product")
public class AccountProductPojo {
    @Id
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "account_id")
    private Long accountId;

    @Column(name = "product_id")
    private Integer productId;

    @ManyToOne
    @JoinColumn(name = "product_id", insertable = false, updatable = false)
    private ProductPojo product;

    @OneToOne(fetch = FetchType.LAZY, targetEntity = AccountPojo.class)
    @JoinColumn(name = "account_id", insertable = false, updatable = false)
    private AccountPojo account;

    // getters and setters
}

Answer:

This seems to be a fairly classic case of mocking a void method.

You could try something like this:

    Mockito.doAnswer(new Answer() {
          public Object answer(InvocationOnMock invocation) {
              Object[] args = invocation.getArguments();
              AccountProductPojo accountProduct = (AccountProductPojo) args[0];
              accountProduct.setProduct(new ProductPojo(PRODUCT_ID_CONSTANT, PRODUCT_NAME_CONSTANT));
              return null;
          }}).when(accountProductRepository).refresh(Mockito.any());

The key here is that when refresh() is called on the mock you call setProduct() on the POJO which was passed as an argument to the refresh() call in order to avoid the later null pointer exception.

Question:

I want to be able to use a test properties files and only override a few properties. Having to override every single property will get ugly fast.

This is the code I am using to test my ability to mock properties and use existing properties in a test case

@RunWith(SpringRunner.class)
@SpringBootTest(classes = MyApp.class)
@TestPropertySource(
      locations = { "classpath:myapp-test.properties" },
      properties = { "test.key = testValue" })
public class EnvironmentMockedPropertiesTest {

   @Autowired private Environment env;
   // @MockBean private Environment env;

   @Test public void testExistingProperty() {
      // some.property=someValue
      final String keyActual = "some.property";
      final String expected = "someValue";
      final String actual = env.getProperty(keyActual);
      assertEquals(expected, actual);
   }

   @Test public void testMockedProperty() {
      final String keyMocked = "mocked.test.key";
      final String expected = "mockedTestValue";
      when(env.getProperty(keyMocked)).thenReturn(expected);
      final String actual = env.getProperty(keyMocked);
      assertEquals(expected, actual);
   }

   @Test public void testOverriddenProperty() {
      final String expected = "testValue";
      final String actual = env.getProperty("test.key");
      assertEquals(expected, actual);
   }

}

What I find is:

  • @Autowired private Environment env;
    • testExistingProperty() and testOverriddenProperty() pass
    • testMockedProperty() fails
  • @MockBean private Environment env;
    • testMockedProperty() passes
    • testExistingProperty() and testOverriddenProperty() fail

Is there a way to achieve what I am aiming for?

Dependencies:

<spring.boot.version>1.4.3.RELEASE</spring.boot.version>
...
<!-- Spring -->
<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot</artifactId>
   <version>${spring.boot.version}</version>
</dependency>
<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-autoconfigure</artifactId>
   <version>${spring.boot.version}</version>
</dependency>
<!-- Starter for testing Spring Boot applications with libraries including JUnit,
   Hamcrest and Mockito -->
<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-test</artifactId>
   <version>${spring.boot.version}</version>
</dependency>

Answer:

Ok i have made this work, you need to use Mockito to accompish what you are looking for:

Maven Dependency

<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <version>2.6.4</version>
</dependency>

Test Class Set up

import static org.mockito.Mockito.*;
import static org.springframework.test.util.AopTestUtils.getTargetObject;

@RunWith(SpringRunner.class)
@SpringBootTest(classes = MyApp.class)
@TestPropertySource(
      locations = { "classpath:myapp-test.properties" },
      properties = { "test.key = testValue" })

public class AnswerTest {

    // This will be only for injecting, we will not be using this object in tests.
    @Autowired
    private Environment env;

    // This is the reference that will be used in tests.
    private Environment envSpied;

    // Map of properties that you intend to mock
    private Map<String, String> mockedProperties;

    @PostConstruct
    public void postConstruct(){
        mockedProperties = new HashMap<String, String>();
        mockedProperties.put("mocked.test.key_1", "mocked.test.value_1");
        mockedProperties.put("mocked.test.key_2", "mocked.test.value_2");
        mockedProperties.put("mocked.test.key_3", "mocked.test.value_3");

        // We use the Spy feature of mockito which enabled partial mocking
        envSpied = Mockito.spy((Environment) getTargetObject(env));

        // We mock certain retrieval of certain properties
        // based on the logic contained in the implementation of Answer class
        doAnswer(new CustomAnswer()).when(envSpied).getProperty(Mockito.anyString());
    }

Test case

    // Testing for both mocked and real properties in same test method
    @Test public void shouldReturnAdequateProperty() {
        String mockedValue = envSpied.getProperty("mocked.test.key_3");
        String realValue = envSpied.getProperty("test.key");

        assertEquals(mockedValue, "mocked.test.value_3");
        assertEquals(realValue, "testValue");
    }

Implementation of Mockito's Answer interface

    // Here we define what should mockito do:
    // a) return mocked property if the key is a mock
    // b) invoke real method on Environment otherwise
    private class CustomAnswer implements Answer<String>{

        @Override
        public String answer(InvocationOnMock invocationOnMock) throws Throwable {
            Object[] arguments = invocationOnMock.getArguments();
            String parameterKey = (String) arguments[0];

            String mockedValue = mockedProperties.get(parameterKey);

            if(mockedValue != null){
                return mockedValue;
            }

            return (String) invocationOnMock.callRealMethod();
        }
    }
}

Try it out, and let me know if all is clear here.

Question:

I'm trying to do the Mockito for a method called generateToken() by using MockitoJUnitRunner.class. The source which I have tried to do as follows.

@RunWith(MockitoJUnitRunner.class)
public class LoginServiceTest {

@Mock
private UserRepository userRepository;

@Mock
private JwtTokenGenerator jwtTokenGenerator;

@InjectMocks
private LoginServiceImpl loginServiceImpl = new LoginServiceImpl();

private JwtUserDto user;

private String jwtSecret;
private String username;
private String password;

/**
 * Initialize test data before test cases execution
 */
@Before
public void init() {

    user = new JwtUserDto();
    user.setId(1L);
    user.setUsername("kray1");
    user.setRole("Admin");

}

@Test
public void testLogin() {

    try {

        Mockito.when(jwtTokenGenerator.generateToken(user, jwtSecret)).thenReturn("myToken");

        String actual = loginServiceImpl.login(username, password);
        assertNotNull(actual);

    } catch (Exception e) {
        e.printStackTrace();
    }

}

For that generateToken() method, I have to pass user object and a string. I'm declaring the user object in Init() method. When I try to execute this, the value return from the login method is null. But when I try to pass the user object as null then it will work as expected. So the problem should be with the user object.

Is there anything, like Mockito is blocking this kind of object with added properties or related thing? Please help to find a way to pass this user object with Mockito.

The LoginServiceImpl class as follows.

public class LoginServiceImpl implements LoginInterface {

@Autowired
private UserRepository userRepository;

@Autowired
private JwtTokenGenerator jwtTokenGenerator;


/*
 * (non-Javadoc)
 */
public String login(String userName, String password) {

    if (userName != null && password != null && !userName.isEmpty() && !password.isEmpty()) {
        List<UserAuthenticationInfo> authInfo = userRepository.findUserRolesByUsernamePassword(userName, password);
        if (authInfo != null && !authInfo.isEmpty()) {
            JwtUserDto user = new JwtUserDto();
            user.setId((long) authInfo.get(0).getUserId());
            user.setUsername(userName);
            user.setRole(authInfo.get(0).getUserRole());

            return jwtTokenGenerator.generateToken(user, jwtSecret);

        }
    }

    return null;
}

}


Answer:

Do you have equals/hashcode on User class?

What is the result if you setup mock using Mockito.when(jwtTokenGenerator.generateToken(any(User.class),any(String.class)) .thenReturn("myToken");

explanation:

When setting expectation as

Mockito.when(jwtTokenGenerator.generateToken(user, jwtSecret)).then...

You instruct your mock to act only for given user object. equals method is used for that. So, if your User is missing equals method, then reference equality is used. Two User objects (each crated with separate new User() call will not be equal.

For non-matching parameters in Mockito.when your mock (thenReturn) is not applied. Default value (null) is returned from mock.

Therefore I prefer to setup mocks not for specific arguments and then use Mockito.verify to check if expected interactions with mock took place. That way your tests are more expressive. Actually most of my object have equals/hashode not because of business reasons (I do not put them in collections) but only for testing and comparing using assertEquals.

Side note:

do not catch (Exception e) { e.printStackTrace(); } in test. It is much easier just to declare test method to throw Exception. End result is same (stacktrace printed) but with less code.

Question:

Hamcrest/jMock code looks like this:

@Test
public void setsSniperValuesInColumns() {
    context.checking(new Expectations() {{
        one(listener).tableChanged(with(aRowChangedEvent())); 
    }});
    model.sniperStatusChanged(new SniperState("item id", 555, 666), MainWindow.STATUS_BIDDING);
    ...
}

private Matcher<TableModelEvent> aRowChangedEvent() {
    return samePropertyValuesAs(new TableModelEvent(model, 0));
}

NB this is taken from "Growing Object-Oriented Software Guided by Tests" (p. 157). The authors of this book use Hamcrest and jMock. I'm of the opinion that AssertJ and Mockito are probably better. Of course it would be possible to use both these testing frameworks in the same projects, but it would get pretty confusing and doesn't seem ideal.

samePropertyValuesAs comes from import static org.hamcrest.beans.SamePropertyValuesAs.samePropertyValuesAs; with appears to come from jMock

So what I'm trying to find is a way that I can use Mockito's verify method where they are using Expectations. But is there any way that I can do this:

verify( listener ).tableChanged( samePropertyValues( new TableModelEvent( model, 0 )));

... of course one can imagine a workaround where you go around setting all the properties one by one... but I would imagine Mockito has something better out of the box.


Answer:

The refEq matcher seems like it's what you're looking for:

verify(listener).tableChanged(refEq(new TableModelEvent(model, 0)));

Question:

I have a @ConfigurationProperties class like this:

@ConfigurationProperties(prefix = "myprops", ignoreUnknownFields = false)
@Configuration
public class MyProperties {

   private Long mySchedulerRate;

   @Bean
   public Long mySchedulerRate() {
       return this.mySchedulerRate;
   } 

}

I'm registering it as a bean so I can refer to it in an annotation for a Spring scheduler:

@Scheduled(fixedRateString = "#{@mySchedulerRate}")
public void runScheduledUpdate() {
   ...
{

However, I now want to write a unit test where I want to be able to set a different value for the bean 'mySchedulerRate'. Mocking/Spying on the @ConfigurationProperties class doesnt seem to work since the scheduler gets set up before the stubbing has been set to return my desired value.

What is the easiest way to achieve what I am trying to do?


Answer:

Managed to fix this now. I was running a @SpringBootTest and I realise you can override properties here within the annotation for a particular test class.

This worked for me:

@RunWith(SpringRunner.class)
@SpringBootTest(classes = MyApp.class, properties = "myprops.my-scheduler-rate=1000")
public class MyTest {

So no need to try and override the bean, I was overcomplicating this far too much.

Question:

I am trying to mock a constructor 'EmailParams' in my test class. Mocking is failing since the constructor EmailParams mocks as null.

Below is my test method

@Test
   public void getContactEmailsByFilterSuccessTest() throws Exception {

    String contactId = "752";
    String emailAddress = "test@gmail.com";
    String emailType = "EW";

    MockHttpServletRequest request = new MockHttpServletRequest();
    when(helper.isNumeric(any(String.class))).thenReturn(true);

    List<ContactXref> sourcedContacts = getContactXrefs();
    when(contactXrefServiceMock.getContactsForId(contactId)).thenReturn(sourcedContacts);

    EmailParams emailParams = new EmailParams("test@gmail.com", "EW", sourcedContacts.get(0).getContact().getContactId().toString());

    List<Email> emailsList = getEmailsList();
    when(emailServiceMock.getEmailByFilter(emailParams)).thenReturn(emailsList);

    ResponseEntity<List<Email>> response = contactControllerMock.getContactEmailsByFilter(request, contactId, emailAddress, emailType);
    Assert.assertEquals("getContactEmailsByFilterSuccessTest: Expected response code to be 200", "200", 
  response.getStatusCode().toString());   
 }

This is the method I am trying to mock. Test fails when its trying to mock the constructor

@GetMapping(value = "/{contactId}/" + UrlMapping.EMAILS, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<List<Email>> getContactEmailsByFilter(HttpServletRequest request,
                                                            @PathVariable(name = RequestParams.CONTACTID) String contacId,
                                                            @RequestParam(required = false, name = RequestParams.EMAILADDRESS) String emailAddress,
                                                            @RequestParam(required = false, name = RequestParams.EMAILTYPE) String emailType)
                                                            throws Exception {


      ResponseEntity response = new ResponseEntity("Only numeric contactId is allowed", HttpStatus.BAD_REQUEST);

      List<Email> emailList;
      List<ContactXref> sourcedContacts;

      if (helper.isNumeric(contactId)) {

          sourcedContacts = contXrefService.getContactsForId(contactId);

          EmailParams params = new EmailParams(emailAddress, emailType, sourcedContacts.get(0).getContact().getContactId().toString());

          emailList = emailService.getEmailByFilter(params);
          if (emailList != null) {
               response = emailList.size() == 0 ? new ResponseEntity("No emails were found for the request", HttpStatus.NOT_FOUND) : new ResponseEntity(emailList, new HttpHeaders(), HttpStatus.OK);
           } else {
              response = new ResponseEntity("Encountered exception in retrieving emails", HttpStatus.INTERNAL_SERVER_ERROR);
          }
      }
       return response;
}

Here is my class which has the constructor.

public class EmailParams {

    String email;
    String emailType;
    String ptyId;

    public EmailParams() {
        super();
    }

    public EmailParams(String pEmail, String pEmailType, String pPtyId) {
        email = pEmail;
        emailType = pEmailType;
        ptyId = pPtyId;
    }
}

How to mock it properly? thanks in advance.


Answer:

If the equals method is not overridden in EmailParams class by default Mockito uses Object.equals to compare the EmailParams passed to getEmailByFilter method. In your case both object properties have same values but still they are different objects. So either override the equals method in EmailParams or use ArgumentMatchers.argThat

 when(emailServiceMock.getEmailByFilter(ArgumentMatchers.argThat(p -> p.getPEmail().equals("test@gmail.com") && condition2 && condition3 )))
                  .thenReturn(emailsList);

Question:

I am trying to write a unit test case to test the method, but I encounter a problem.

here is the sample code:

MyService1

@Service
public class MyService1 {

    @Autowired
    private ServiceProperties serviceProperties;

    public void getMyLanguage(){
        String language =  serviceProperties.getLocale().getLanguage();
        printSomething(language);
    }

    private void printSomething(String input){
        System.out.print("your current language is " + input);
    }
}

ServiceProperties

import org.springframework.boot.context.properties.ConfigurationProperties;

import java.util.Locale;

@ConfigurationProperties(prefix = "conversation")
public class ServiceProperties {

    private ServiceProperties(){};

    private Locale locale;

    public Locale getLocale(){

        return locale;

    }
}

application.properties

conversation.locale=en_US

Here is my test case:

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;

import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

@RunWith(MockitoJUnitRunner.class)
public class MyService1Test {
    @Mock
    private ServiceProperties serviceProperties;

    @InjectMocks
    private MyService1 myService1;

    @Test
    public void getMyLanguage(){
        when(serviceProperties.getLocale().getLanguage()).thenReturn("EN");
        myService1.getMyLanguage();
        verify(myService1).getMyLanguage();
    }
}

the test will trigger nullpointerexception, because the properties for locale are not loaded in test, if I don't want to start the server(use @SpringBootTest annotation) to load the context, is there any way to solve this problem, can anyone help?


Answer:

The problem is at this line:

when(serviceProperties.getLocale().getLanguage()).thenReturn("EN");

Because serviceProperties is mocked, serviceProperties.getLocale() is equal to null. So you get NullPointerException when serviceProperties.getLocale().getLanguage() is called.

One workaround would be as follows:

@RunWith(MockitoJUnitRunner.class)
public class MyService1Test {
    @Mock
    private ServiceProperties serviceProperties;
    @InjectMocks
    private MyService1 myService1;

    @Test
    public void getMyLanguage(){
        when(serviceProperties.getLocale()).thenReturn(new Locale("EN"));
        myService1.getMyLanguage();
        verify(myService1).getMyLanguage();
    }
}

Question:

I'm changing our identity strategy and we're using an ID that is generated before the Entity is written to the database. This change is causing some of our tests to fail due to the way we're mocking some service calls.

TimeLog timeLog = buildTimeLog('123456', mockEmployeeId);
TimeLog mockTimeLog = buildTimeLog('123456', mockEmployeeId);
when(this.timeLogService.save(mockTimeLog)).thenReturn(timeLog);

When the test makes the call to the Controller, the bound entity in the Controller gets a different ID than the mock that is expected because the Entity generates the ID. Whereas before, the database generated the ID so the mocks worked.

If there is a way to tell Mockito to ignore a property in the expectation? That would solve the problem and the test would still be valid. Otherwise, other approaches are welcome.


Answer:

You can't tell mockito to ignore a property in an expectation because it's using the java "equals" method... You can define an equals method in TimeLog that igonres ID but I suspect that won't give you what you want. The other approach is, instead of trying to tell mockito what not to verify, define explicitly what it is to verify using a hamcrest matcher. Define a hamcrest matcher which just matches the fields you want to verify i.e. all fields other than ID. So something like:

private class TimeLogMatcher extends TypeSafeMatcher<TimeLog> {
    private final EmployeeId employeeId;

    public TimeLogMatcher(EmployeeId employeeId) {
        this.employeeId = employeeId;
    }

    @Override
    public void describeTo(Description description) {
        description.appendText("TimeLog with employeeId=" + employeeId);
    }

    @Override
    public boolean matchesSafely(TimeLog item) {
        return employeeId.equals(item.getEmployeeId());
    }
}

And then instead of calling whatever your "buildTimeLog" method is doing call into the mockito Matchers class like:

TimeLog timeLog = Matchers.argThat(new TimeLogMatcher(mockEmployeeId));

Or alternatively you could always use an Answer object:

when(this.timeLogService.save(any(TimeLog.class)).thenAnswer(new Answer<TimeLog> {
    public TimeLog answer(InvocationOnMock invocation) throws Throwable {
        TimeLog receivedTimeLog = invocation.getArgumentAt(0, TimeLog.class);
        assertThat(receivedTimeLog.getEmployeeId(), equalTo(mockEmployeeId));
        return timeLog;
    }
});

Does that all make sense?