How to mock void methods with Mockito while writing unit tests in Java?
Some times the method you are unit testing, has a dependency on a method that does not return any value, but has a void return type. To mock such methods we can not use the `when-thenReturn` or `doReturn-when` pattern.
Our simple expectation from the `Void` dependency method could be that it throws an exception or does not perform any internal action.
Mockito provides two constructs `doThrow-when` and `doNothing-when` to test the above scenarios.
Mockito.doThrow(new Exception()).when(mockObject).methodName();
Mockito.doNothing().when(mockObject).methodName();
Let's look at an example to understand the above two scenarios.
Let's consider our PersonService class and PersonRepository class. We would be writing unit tests for the `delete()` method of PersonService class. The `delete()` method of PersonService class is dependent on `delete()` method of PersonRepository class, which has return type as `void`. PersonRepository is a Spring JPA repository, hence it provides these methods implicitly.
public class PersonService {
private final PersonRepository personRepository;
public PersonService(PersonRepository personRepository) {
this.personRepository = personRepository;
}
public void delete(Long id) {
Person person = new Person();
person.setId(id);
personRepository.delete(person);
}
}
public interface PersonRepository extends JpaRepository<Person, Long> {
}
The following test class shows how to write unit test to check for success and exception case.
class PersonServiceTest {
/**
* Verify successful execution of tested method, by setting dependency method to do nothing.
*/
@Test
void create_success() {
// Create mock of PersonRepository
PersonRepository mockPersonRepository = Mockito.mock(PersonRepository.class);
// Create PersonService class and inject mocked PersonRepository object to it.
PersonService personService = new PersonService(mockPersonRepository);
// Setup do nothing expectation of PersonRepository
Mockito.doNothing().when(mockPersonRepository).delete(Mockito.any(Person.class));
// Call tested method
personService.delete(34L);
// Verify that delete() method of PersonRepository was called by the delete() method od PersonService.
Mockito.verify(mockPersonRepository).delete(Mockito.any(Person.class));
}
/**
* Verify exception is throw by the tested method if dependent method throws exception.
*/
@Test
void create_exception() {
// Create mock of PersonRepository
PersonRepository mockPersonRepository = Mockito.mock(PersonRepository.class);
// Create PersonService class and inject mocked PersonRepository object to it.
PersonService personService = new PersonService(mockPersonRepository);
// Setup expectation of delete() method of PersonRepository to throw exception
Mockito.doThrow(new RuntimeException("Invalid Argument")).when(mockPersonRepository).delete(Mockito.any(Person.class));
// Call tested method, and verify that it throws an exception
Assertions.assertThrows(RuntimeException.class, () -> personService.delete(100L));
}
}
0 comments:
Post a Comment