Value For Variable Not Overwritten When Using Mockito - java

Apologies if I may be misunderstanding how Mockito works, but I'm trying to test for the case when one of my properties is null, setting it through mockito but it won't overwrite that unless I set the value for the whole object as null or make into a method and mock that instead and with the use of a spy.
Please let me try to better explain this with my code.
This is my class and the piece I want to test for. I'm checking the case where something wrong happens on saving a follower to a user so that is not set and returned empty. To be honest, I'm also not sure if it makes sense to test this with an if or whether I should be catching some exception here. But back to the original problem, the followerEntity object is always being created with the params for userTo and userFrom and this is what I'm trying to have mockito overwrite as null on the save call but in a way that it would return the other values for the user object. I'm not too sure, however, where I may be getting this wrong.
#Mock
UserRepository userRepository;
#Spy
#InjectMocks
UserServiceImpl userService;
#Override
public void followUser(UUID fromId, UUID toId) throws FollowerNotFoundException {
Optional<UserEntity> userEntityOptionalFrom = userRepository.findById(fromId);
Optional<UserEntity> userEntityOptionalTo = userRepository.findById(toId);
if (userEntityOptionalFrom.isEmpty() || userEntityOptionalTo.isEmpty()) {
throw new UserNotFoundException("No user found with this id");
}
UserEntity userEntityTo = userEntityOptionalTo.get();
UserEntity userEntityFrom = userEntityOptionalFrom.get();
Set<FollowingRequestEntity> followingRequestEntities = new HashSet<>();
FollowingRequestEntity followingRequestEntity = FollowingRequestEntity.builder().userSenderEntity(userEntityFrom).userReceiverEntity(userEntityTo).build();
followingRequestEntities.add(followingRequestEntity);
userEntityTo.setFollowedByEntity(followingRequestEntities);
userEntityTo = userRepository.save(userEntityTo);
if (userEntityTo.getFollowedByEntity() == null || userEntityTo.getFollowedByEntity().isEmpty()) {
throw new FollowerNotFoundException("Follower Not Found");
}
}
public UserEntity setFollower(UserEntity userEntityTo, UserEntity userEntityFrom) { // The tests work if calling and mocking this instead
Set<FollowingRequestEntity> followingRequestEntities = new HashSet<>();
FollowingRequestEntity followingRequestEntity = FollowingRequestEntity.builder().userSenderEntity(userEntityFrom).userReceiverEntity(userEntityTo).build();
followingRequestEntities.add(followingRequestEntity);
userEntityTo.setFollowedByEntity(followingRequestEntities);
return userEntityTo;
}
This is what I have for my test. As you can see, I've tried both when..Return() and doReturn() and also forcing the follower entity values to null, but when debugging my user object it always shows the FollowerBy property populated and not null.
#Test
void testFollowUser_ThrowsExceptionWhenFollowerIsFound() {
UUID userFromId = randomUUID();
UUID userToId = randomUUID();
UserEntity userEntityFrom = getUserEntity();
userEntityFrom.setId(userFromId);
UserEntity userEntityTo = getUserEntity();
userEntityTo.setId(userToId);
userEntityTo.setName("new name");
when(userRepository.findById(userEntityFrom.getId())).thenReturn(Optional.of(userEntityFrom));
when(userRepository.findById(userEntityTo.getId())).thenReturn(Optional.of(userEntityTo);
// when(userRepository.save(userEntityTo)).thenReturn(userEntityTo);
userEntityTo.setFollowerOfEntity(null);
userEntityTo.setFollowedByEntity(null);
doReturn(userEntityTo).when(userRepository).save(any());
// when(userEntityTo.getFollowedByEntity()).thenReturn(null);
// doReturn(userEntityTo).when(userService).setFollower(any(), any());
FollowerNotFoundException exception =
assertThrows(FollowerNotFoundException.class, () -> userService.followUser(userFromId, userToId));
assertEquals("Follower Not Found", exception.getMessage());
}
Thank you very much.

Here's a complete example (compressed into a single file) which explains what I have been trying to get across in the comments above:
package com.example.demo;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.when;
class MyService {
private final MyRepository myRepository;
MyService(MyRepository myRepository) {
this.myRepository = myRepository;
}
public String doWork() {
return myRepository.get().toUpperCase();
}
}
class MyRepository {
public String get() {
return "a real thing from the DB";
}
}
#ExtendWith(MockitoExtension.class)
public class MyTests {
#Mock
MyRepository myRepository;
#InjectMocks
MyService myService;
#Test
public void aTest() {
when(myRepository.get()).thenReturn("something fake");
assertEquals("SOMETHING FAKE", myService.doWork());
}
}
The actual non-test code (which will live in src/main/java) is MyService and MyRepository. These classes have no reference to any test code.
MyTests is in src/test/java. It's the only part of your code which knows about mocks.
We can remove some of the "magic" by explicitly creating and injecting the mocks:
...
MyRepository myRepository;
MyService myService;
#BeforeEach
public void setup() {
myRepository = mock(MyRepository.class);
myService = new MyService(myRepository);
}
...
Looking at the function you are testing we see:
followingRequestEntities.add(followingRequestEntity);
userEntityTo.setFollowedByEntity(followingRequestEntities);
userEntityTo = userRepository.save(userEntityTo);
if (userEntityTo.getFollowedByEntity() == null || userEntityTo.getFollowedByEntity().isEmpty()) {
throw new FollowerNotFoundException("Follower Not Found");
}
So as followingRequestEntities always contains one entry, userEntityTo.getFollowedByEntity().isEmpty() will always be false, no matter what your mocks return, and the exception can never be thrown.
You can use:
when(userRepository.findById(userEntityFrom.getId())).thenReturn(Optional.empty());
and expect that UserNotFoundException will be thrown.

Related

Mock returned value of ResultSet inside the method to be tested that implements an interface

I'm trying to mock some data with Mockito for some tests, but I can't get it to work. My problem is that the value I want to mock is the return of a call inside the method I need to test.
I have a class, MyAccessor.java (that implements a service, MyService.java) that inside has a method, getMyMethod(String value), and inside that method there is a call to the DB:
final List<MyType> results = this.jdbcTemplate.query(sqlQuery, new RowMapper<MyType>() {
#Override
public MyType mapRow(final ResultSet rs, final int rowNum) throws SQLException {
final int fieldA = rs.getInt("column_name_1");
final int fieldB = rs.getInt("column_name_2");
final int fieldC = rs.getInt("column_name_3");
final int fieldD = rs.getInt("column_name_4");
return new MyType(fieldA , fieldB , fieldC , fieldD);
}
}, value);
There is a case where due to timeouts with the database, an empty list is returned by the rowMapper. So in that case it is not possible to do return results.get(0) because you will get an ArrayIndexOutOfBoundsException.
So I have a check:
if (!results.isEmpty()) {
return results.get(0);
} else {
return new MyType(0, 0, 0, 0);
}
Now, I want to test this particular scenario but I don't know how to mock the resultSet return so that the rowMapper returns an empty list. In my test class I have set:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { ".....", "....."})
#TestPropertySource(".....")
public class MyClassTest {
#Mock
private JdbcTemplate jdbcTemplate;
#InjectMocks
#Autowired
private MyService myService;
#Before
public void initMocks() {
MockitoAnnotations.openMocks(this);
}
#Test
public void myTestMethod() {
Mockito.when(this.jdbcTemplate.query("SELECT NULL LIMIT 0", new RowMapper<Object>() {
#Override
public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
return new ArrayList<>();
}
})).thenReturn(new ArrayList<Object>());
MyType result = this.myService.getMyMethod("value");
assertEquals(0, result.getFieldA());
assertEquals(0, result.getFieldB());
assertEquals(0, result.getFieldC());
assertEquals(0, result.getFieldD());
}
}
But the test fails because the result returned is from the database instead of an empty list to test the timeout case.
I think the problem may be because I'm injecting the mock in the service interface instead of the implementation, but I wanted to know if it can be done somehow so I don't have to test the mock for each implementation of that interface.
Or maybe I am using the Mockito framework wrong and in that case, how can I test correctly?
Regads.
I think you want something more like:
#Test
public void myTestMethod() {
Mockito.when(this.jdbcTemplate.query(eq("SELECT NULL LIMIT 0"), Mockito.any(RowMapper.class))
.thenReturn(new ArrayList<Object>());
}
Reason is because when mocking, you were saying only to return the empty list if both arguments to the query is exactly as you defined. In your case, you don't care about the exact instance of RowMapper.
I have found the problem. I was injecting the mock in the interface and not in the implementation of the interface. So I had to change:
#Mock
private JdbcTemplate jdbcTemplate;
#InjectMocks
#Autowired
private MyService myService;
to:
#Mock
private JdbcTemplate jdbcTemplate;
#InjectMocks
#Autowired
private MyAccessor myAccessor;
#Autowired
private MyService myService;
And inside the test this:
MyType result = this.myService.getMyMethod("value");
to:
MyType result = this.myAccessor.getMyMethod("value");
I don't know if there is a better way to do this, without having to instantiate all the implementations that the service may have.
Regards.

Mockito mock same method calls with different collection-arguments

I try to mock same method calls with different collection-arguments.
My problem is that im not getting the correct mocked-answer from Mocked-Call for the input.
Test-Class:
#ExtendWith(SpringExtension.class)
public class CollectionTest {
#MockBean
private Controller c;
#BeforeEach
public void init() {
Collection<String> a = Mockito.anyCollection();
a.add("a");
Mockito.when(c.run(a)).thenReturn("a");
Collection<String> b = Mockito.anyCollection();
b.add("b");
Mockito.when(c.run(b)).thenReturn("b");
}
#Test
public void test() {
assertEquals("a", c.run(Lists.newArrayList("a"))); // DOESNT'WORK!!! Returns "b" but should "a"
assertEquals("b", c.run(Lists.newArrayList("b"))); //
}
}
Controller-Class:
#Service
public class Controller{
public String run(Collection<String> c) {
return "not-mocked";
}
}
I'v got no idea why it doesn't return "a". I tried to change the collection to string but same behaviour.
What are the Steps to do, to get the following behaviour?
#Test
public void test() {
assertEquals("a", c.run(Lists.newArrayList("a"))); // should return "a"
assertEquals("b", c.run(Lists.newArrayList("b"))); // should return "b"
}
Im using Java Mockito "3.1" and Spring, but I think Mockito is the important information here.
Your second call - Mockito.when(c.run(b)).thenReturn("b");
is overruling our first call so Mockito will therefore always return "b".
If you need multiple answers from the same call, you can use the varags variant:
when(c.run(anyCollection())).thenReturn("a", "b");
Now the first call to the controller's run method will return "a" and all subsequent calls will return "b". You can provide as many return results as you want and the last one will be repeated from then on as the answer.
Write two tests will show you the results you are expecting.
You are adding to the same Controller two different results so you get only the last one : Mockito.when(c.run(b)).thenReturn("b");
Normal. The last mocked expected result in your setUp() will stay in memory.
Previous answer was :
You can use something like junit and mockito to test your spring-web-mvc application.
It looks like that :
#WebMvcTest(controllers = UserController.class)
#ActiveProfiles("test")
class UserControllerTest {
#Autowired
private MockMvc mockMvc;
#MockBean
private UserService userService;
private List<User> userList;
#BeforeEach
void setUp() {
this.userList = new ArrayList<>();
this.userList.add(new User(1L, "user1#gmail.com", "pwd1","User1"));
this.userList.add(new User(2L, "user2#gmail.com", "pwd2","User2"));
this.userList.add(new User(3L, "user3#gmail.com", "pwd3","User3"));
}
}
And as an example :
#Test
void shouldFetchAllUsers() throws Exception {
given(userService.findAllUsers()).willReturn(userList);
this.mockMvc.perform(get("/api/users"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.size()", is(userList.size() )));
}
Example from #see https://medium.com/backend-habit/integrate-junit-and-mockito-unit-testing-for-controller-layer-91bb4099c2a5

Problems with null pointer using mockito

I'm trying to test a method. And in this method, a new Object is instancied, but I don't want it, otherwise other class will be tested.
How I tell to mockito dont intanciate it?
#Component
#EnableScheduling
public class VerificadorDeNovasAssinaturas {
private DocuSign docuSign;
private ApiClient apiClient;
#Autowired
private DocuSignProperties docuSignProperties;
public EnvelopesInformation verificaNovasAssinaturas() throws Exception {
this.docuSign = new DocuSign(docuSignProperties); // I don't want mockito instanciate DocuSign
this.apiClient = docuSign.getApiClient();
this.apiClient.addDefaultHeader("Authorization", "Bearer " + docuSign.getoAuthToken().getAccessToken());
And my test class:
#SpringBootTest
#RunWith(SpringRunner.class)
#ActiveProfiles("test")
public class VerificadorDeNovasAssinaturasTest {
#InjectMocks
private VerificadorDeNovasAssinaturas verificador;
private DocuSignProperties docuSignProperties;
private ApiClient apiClient;
private UserInfo userInfo;
private OAuthToken oAuthToken;
#Mock
private DocuSign docuSign;
#Before
public void initialize() throws Exception {
docuSignProperties = new DocuSignProperties();
docuSignProperties.setBaseUrl("https://demo.docusign.net/restapi");
docuSignProperties.setBasePath("/restapi");
setApiClientConfigurations();
when(docuSign.getApiClient()).thenReturn(this.apiClient);
when(docuSign.getoAuthToken()).thenReturn(this.oAuthToken);
...}
private void setApiClientConfigurations() throws Exception {
this.apiClient = new ApiClient(this.docuSignProperties.getBaseUrl());
this.oAuthToken = getOAuth();
... }
#Test
public void testaVerificacaoDeNovasAssinaturas() throws Exception {
EnvelopesInformation results = verificador.verificaNovasAssinaturas();
assertNotNull(results);
}
I don't want mockito instanciate a new DocuSign, because this is not the reason of the test. There is some way do ignore this step?
Well, Mockito can not change something if your code( Code to be tested, Which you intend to) does something, However you can mock it so that it does not create a new object (rather have your "Mocked Object"), so that you can verify something against the expected behavior.
In your code if you change few lines , you can achieve what you want, like -
Create a DocuSignService class and there you create this new object in say some - getDocuSign method. Then your code looks something like below -
#Autowired
private DocuSignService docuSignService ;
this.docuSign = new DocuSign(docuSignProperties); // This is what you have
this.docuSign = this.docuSignService.getDocuSign() ; // This is new code
Now in your test case -
#Mock
DocuSignService docuSignService ;
#Mock
private DocuSign docuSign;
//.
//.
Mockito.when(this.docuSignService.getDocuSign()).thenReturn(docuSign);
Now you have control on this object.
I resolved it using powerMockito.
DocuSign docuSign = PowerMockito.mock(DocuSign.class);
PowerMockito.whenNew(DocuSign.class).withAnyArguments().thenReturn(docuSign);

Mockito default behaviour and custom behaviour with methods with identical return types

Supossing I have the following code to test UserController by mocking UserService (where UserController has a reference to UserService):
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
...
public class UserControllerTest {
private final List<User> users1 = new ArrayList<>();
private final List<User> users2 = new ArrayList<>();
#Before
public void initUsers() {
User user = new User();
user.setId(1L);
users1.add(user);
User user = new User();
user.setId(2L);
users2.add(user);
}
#Test
public void testFindAlls() throws Exception {
UserService userService = mock(UserService.class); //line1
when(userService.findAll1()).thenReturn(users1); //line2
when(userService.findAll2()).thenReturn(users2); //line3
UserController userController = new UserController();
ReflectionTestUtils.setField(userController, "userService", userService);
List<User> users3 = userController.findAll1(); //line4
List<User> users4 = userController.findAll2(); //line5
...
}
}
I have the following doubts:
When the line1 is reached, what would be the default behaviour for userService.findAll1() and userService.findAll2()?
When the line3 is reached, as userService.findAll1() and userService.findAll2() return the same result type (List<User>). Will the line3 override the behaviour defined in line2? I mean, will userService.findAll1() return users2 instead of users1?
I mean, the when method signature is public static <T> OngoingStubbing<T> when(T methodCall) so T in the example would be an element of type List<User> with the value probably to null. So, how the when method is able to determine that different calls are passed as arguments?
1.
When you mock something all methods - that have a return type - would just return null by default (or equivalents in case of primitives). Since the mock has no implementation on its own, a call to the method is doing nothing (basically it handles like an empty method).
2.
Why would that be? You map different return values to different methods, there is no possibility of overriding something.
Edit3:
I just removed my previous try to expalin this. The content of the link is better than anything I can come up with. So it's not easy to understand.
How does mockito when() invocation work?
On another note:
You might not need to use Reflections to put the mock into your object. Check out #InjectMocks & #Mock. So wheter you can use them (or how to use them) depends on your JUnit and Mockito version.
(How to use Mockito with JUnit5)

Java Mockito is hitting real method rather than using mocked method

My mockito method is hitting the real method rather than invoking the mocked method. Your inputs will be helpful
Java code.
public class CheckUser {
private final UserDao userDao;
public CheckUser (final String domain){
userDao = new UserDao(domain);
}
public IUser getExistingUser(){
if (userDao == null) {
throw new RuntimeException("userDao is null");
}
IUser existingUser = userDao.getExistingUser();
if (existingUser == null) {
throw new RuntimeException("ExistingUser is null");
}
return existingUser;
}
}
This is my JUnit test code.
#Test
public void testExistingUser() {
UserDao mockUserDao = mock(UserDao.class);
when(mockUserDao.getExistingUser()).thenReturn(getExistingTestUser());
}
private UserDao getExistingTestUser(() {
return ExistingUserImpl.Builder(). //withfield methods. build();
}
I am creating this mock object for only testing purpose. This just return the mocked MockedExistingUserImpl object which is implemented by IUser.
public class MockedExistingUserImpl implements IUser {
//fields
//overriding getter methods for all fields
//Builder for ExistingUserImpl
}
When ever I call userDao.getExistingUser() in my code, I am expecting to return the mocked Existing user object but it is hitting the real method and failing the test due to domain connection. We don't establish a domain connection to run Junits. Any inputs are appreciated. Thank you !
The answer is to read a tutorial about Mockito and follow that. You make the typical mistake: you create a mock object, but then you don't do anything so that your production code uses that mocked object.
Just doing a mock(YourClass) doesn't magically change that new() in your production code to return a mocked instance.
You need to inject that mocked instance into the code under test. For example by using the #InjectMock annotation.
For a good intro, see https://www.baeldung.com/Mockito-annotations for example.
And note: as written right now, you will have a hard time to use Mockito for your tests. Due to the direct call to new(), you would need PowerMock(ito) to test it. So: learn how to use Mockito, and then rework your production code to be easily testable. (turning to PowerMock would be the wrong strategy).
Your mistake is in broken 'Dependency injection' principle.
Don't use new operator - create UserDao at the level above and use injection.
public class CheckUser {
private final UserDao userDao;
public CheckUser (final UserDao usedDao) {
this.userDao = userDao;
}
public IUser getExistingUser() {
if (userDao == null) {
throw new RuntimeException("userDao is null");
}
IUser existingUser = userDao.getExistingUser();
if (existingUser == null) {
throw new RuntimeException("ExistingUser is null");
}
return existingUser;
}
}
Now you can test your code in the following way:
#Test
public void testExistingUser() {
UserDao mockUserDao = mock(UserDao.class);
when(mockUserDao.getExistingUser()).thenReturn(getExistingTestUser());
CheckUser checkUser = new CheckUser(mockUserDao);
IUser iUser = checkUser.getExistingUser();
// assertions here
}
private UserDao getExistingTestUser(() {
return ExistingUserImpl.Builder(). //withfield methods. build();
}

Categories