Mockito - thenReturn always returns null object - java

I'm trying to implement Mockito to test a particular method but the .thenReturn(...) seems to always be returning a null object instead of what I intended:
CUT:
public class TestClassFacade {
// injected via Spring
private InterfaceBP bpService;
public void setBpService(InterfaceBP bpService) {
this.bpService = bpService;
}
public TestVO getTestData(String testString) throws Exception {
BPRequestVO bpRequestVO = new BPRequestVO();
bpRequestVO.setGroupNumber(testString) ;
bpRequestVO.setProductType("ALL") ;
bpRequestVO.setProfileType("Required - TEST") ;
IBPServiceResponse serviceResponse = bpService.getProduct(bpRequestVO); //PROBLEM
if (serviceResponse.getMessage().equalsIgnoreCase("BOB")) {
throw new Exception();
} else {
TestVO testVO = new TestVO();
}
return testVO;
}
}
Spring Configuration:
<bean id="testClass" class="com.foo.TestClassFacade">
<property name="bpService" ref="bpService" />
</bean>
<bean id="bpService" class="class.cloud.BPService" />
Mockito Test Method:
#RunWith(MockitoJUnitRunner.class)
public class BaseTest {
#Mock BPService mockBPService;
#InjectMocks TestClassFacade mockTestClassFacade;
private String testString = null;
private BPRequestVO someBPRequestVO = new BPRequestVO();
private IBPServiceResponse invalidServiceResponse = new BPServiceResponse();
#Test (expected = Exception.class)
public void getBPData_bobStatusCode_shouldThrowException() throws Exception {
invalidServiceResponse.setMessage("BOB");
someBPRequestVO.setGroupNumber(null);
someBPRequestVO.setProductType("ALL");
someBPRequestVO.setProfileType("Required - TEST");
System.out.println("1: " + someBPRequestVO.getGroupNumber());
System.out.println("2: " + someBPRequestVO.getProductType());
System.out.println("3: " + someBPRequestVO.getProfileType());
System.out.println("4: " + someBPRequestVO.getEffectiveDate());
when(mockBPService.getProduct(someBPRequestVO)).thenReturn(invalidServiceResponse);
mockTestClassFacade.getTestData(testString);
verify(mockBPService).getProduct(someBPRequestVO);
}
}
System output:
1: null
2: ALL
3: Required - TEST
4: null
What's happening here is that when I run the test the serviceResponse object is null on the line in the CUT marked with //PROBLEM above. My desire is to have that object be populated with my "invalidServiceResponse" object from my test method. Judging from the output of my System.out.println's it appears that my bpRequestVO matches my someBPRequestVO in content.
Could some one show me what I'm missing here?
Thanks for your time!

Instead of creating a equals method in your BPRequestVO class you can create a mock argument with "any(YourObject.class)" like this:
when(mockBPService.getProduct(any(BPRequestVO.class))).thenReturn(invalidServiceResponse);

The instance of BPRequestVO that you use with when() is different than the one used in getTestData().
Unless you override equals(), they will not match.
You should not need to write a custom Matcher if you override equals(). Note the following from the Mockito documentation:
"Custom argument matchers can make the test less readable. Sometimes it's better to implement equals() for arguments that are passed to mocks (Mockito naturally uses equals() for argument matching). This can make the test cleaner."

The problem is in your usage of when().
You submit a reference to a constructed instance; as a result, the mocking will return what you want only if the argument passed to the method is the same reference.
What you want is an argument matcher; something like:
when(mockBPService.getProduct(argThatMatches(someBPRequestVO))
.thenReturn(whatYouWant);
Of course, it requires that you write the argument matcher!
Note that there is a builtin matcher which can do what you want:
when(mockBPService.getProduct(eq(someBPRequestVO))).thenReturn(whatYouWant);
This matcher of course requires that your BPRequestVO class implements equals() (and hashCode() too)!

My problem was that mocked services were defined as final.

The BPRequestVO Object instance used for mocking is different than Instance used while junit execution.
The best way is to configure any instance of the object while mocking
when(mockBPService.getProduct(someBPRequestVO)).thenReturn(invalidServiceResponse);
Can be updated with
when(mockBPService.getProduct(Mockito.any(BPRequestVO.class))).thenReturn(invalidServiceResponse);

My issue was passing null as method arguments doesn't match the when() clause I set up.
e.g.
Car car = mock(Car.class)
when(car.start(anyString()).thenReturn("vroom");
assertEquals("vroom", car.start(null));
This would fail.
assertEquals("vroom", car.start("Now"));
This passes.

My issue was with the instance of the service which is autowired/mockbean had different instance at the Test->given() part and whi lein the execution it had different instance.
This was found by running the test in debug mode and checking each value in the mock stub and execution code. If all the parameters and the mocked instance are same then only the thenReturn() will return the expected value.
In myscenario the mocked instance of the class had multiple implementations and by adding #Qualifier("name") the instance became same in the given() and real execution.

it may also happened in multi-thread case. the mocked object's handler been reset by mockito after the return of #Test method while somewhere(another Thread) still using the mocked object.
as for the situation Thread provided by a pool, you can mock a thread pool instead, executing the Runner.run() in current Thread is proved effective.

Related

Mockito WrongTypeOfReturnValue: Boolean cannot be returned by findById()

I am trying to test the following method with JUnit tests, using Mockito:
#Override public List<Adoption> search(String username, Integer id) {
List<Adoption> emptySearchResult = new ArrayList<>();
if(id != null && !username.equals("") ) {
if(!this.petRepository.findById(id).isPresent()){
return emptySearchResult;
}
if(!this.appUserRepository.findByUsername(username).isPresent()){
return emptySearchResult;
}
Pet pet = this.petRepository.findById(id).orElseThrow( () -> new PetNotFoundException(id));
AppUser user = this.appUserRepository.findByUsername(username).orElseThrow( () -> new UsernameNotFoundException(username));
return this.adoptionRepository.findAllByUserAndPet(user, pet);
}
else if(id != null && username.equals("")){
if(!this.petRepository.findById(id).isPresent()){
return emptySearchResult;
}
Pet pet = this.petRepository.findById(id).orElseThrow( () -> new PetNotFoundException(id));
return this.adoptionRepository.findAllByPet(pet);
}
else if(id == null && !username.equals("")) {
if(!this.appUserRepository.findByUsername(username).isPresent()){
return emptySearchResult;
}
AppUser user = this.appUserRepository.findByUsername(username).orElseThrow( () -> new UsernameNotFoundException(username));
return this.adoptionRepository.findAllByUser(user);
}
else {
return this.adoptionRepository.findAll();
}
}
However, I run into a problem with the following part:
if(!this.petRepository.findById(id).isPresent())
Even though I have mocked this.petRepository.findById(id), for some reason isPresent() is returning false. This is my initialization for the tests:
#Mock
private AdoptionRepository adoptionRepository;
#Mock
private PetRepository petRepository;
#Mock
private AppUserRepository appUserRepository;
private AdoptionServiceImpl service;
private Adoption adoption1;
private Adoption adoption2;
private Adoption adoption3;
private AppUser user;
private AppUser user2;
private Pet pet;
private Pet petAlteadyAdopted;
List<Adoption> allAdoptions = new ArrayList<>();
List<Adoption> userFilteredAdoptions = new ArrayList<>();
List<Adoption> petFilteredAdoptions = new ArrayList<>();
#Before
public void init() {
MockitoAnnotations.initMocks(this);
user = new AppUser("username","name","lastname","email#gmail.com","pass",ZonedDateTime.now(), Role.ROLE_USER, City.Skopje);
user2 = new AppUser("username1","name","lastname","email#gmail.com","pass",ZonedDateTime.now(), Role.ROLE_USER, City.Skopje);
Center center = new Center("a", City.Bitola,"url");
pet = new Pet("p", Type.DOG,"b", Gender.FEMALE,"d",center, ZonedDateTime.now(),"url",null,false,ZonedDateTime.now());
petAlteadyAdopted = new Pet("p", Type.DOG,"b", Gender.FEMALE,"d",center, ZonedDateTime.now(),"url",null,true,ZonedDateTime.now());
pet.setId(0);
petAlteadyAdopted.setId(1);
adoption1 = new Adoption(ZonedDateTime.now(),ZonedDateTime.now(),Status.ACTIVE,user,pet);
adoption2 = new Adoption(ZonedDateTime.now(),ZonedDateTime.now(),Status.CLOSED,user,pet);
adoption3 = new Adoption(ZonedDateTime.now(),ZonedDateTime.now(),Status.CLOSED,user2,new Pet());
allAdoptions.add(adoption1);
allAdoptions.add(adoption2);
allAdoptions.add(adoption3);
petFilteredAdoptions.add(adoption2);
petFilteredAdoptions.add(adoption1);
userFilteredAdoptions.add(adoption2);
userFilteredAdoptions.add(adoption1);
Mockito.when(this.adoptionRepository.findById(0)).thenReturn(java.util.Optional.of(adoption1));
Mockito.when(this.adoptionRepository.findById(1)).thenReturn(java.util.Optional.of(adoption2));
Mockito.when(this.petRepository.findById(0)).thenReturn(java.util.Optional.of(pet));
Mockito.when(this.petRepository.findById(1)).thenReturn(java.util.Optional.of(petAlteadyAdopted));
Mockito.when(this.appUserRepository.findByUsername("username")).thenReturn(java.util.Optional.of(user));
Mockito.when(this.appUserRepository.findByUsername("username1")).thenReturn(java.util.Optional.of(user2));
Mockito.when(this.adoptionRepository.findAll()).thenReturn(allAdoptions);
Mockito.when(this.adoptionRepository.findAllByPet(pet)).thenReturn(petFilteredAdoptions);
Mockito.when(this.adoptionRepository.findAllByUser(user)).thenReturn(userFilteredAdoptions);
Mockito.when(this.adoptionRepository.findAllByUserAndPet(user,pet)).thenReturn(userFilteredAdoptions);
Mockito.when(this.adoptionRepository.save(Mockito.any(Adoption.class))).thenReturn(adoption1);
this.service = Mockito.spy(new AdoptionServiceImpl(this.adoptionRepository, this.petRepository,this.appUserRepository));
}
As a result, the following test fails, even though it should pass:
#Test
public void searchTest2() {
List<Adoption> adoptionList = this.service.search("",0);
Assert.assertEquals(petFilteredAdoptions,adoptionList);
}
In order to solve this I tried mocking the isPresent() method:
Mockito.when(this.petRepository.findById(0).isPresent()).thenReturn(true);
But I'm getting the following exception:
org.mockito.exceptions.misusing.WrongTypeOfReturnValue:
Boolean cannot be returned by findById() findById() should return
Optional***
If you're unsure why you're getting above error read on. Due to the
nature of the syntax above problem might occur because:
This exception might occur in wrongly written multi-threaded tests. Please refer to Mockito FAQ on limitations of concurrency
testing.
A spy is stubbed using when(spy.foo()).then() syntax. It is safer to stub spies -
with doReturn|Throw() family of methods. More in javadocs for Mockito.spy() method.
I also tried the following variation:
Mockito.doReturn(true).when(this.petRepository.findById(0)).isPresent();
But then I got the following exception:
org.mockito.exceptions.misusing.UnfinishedStubbingException:
Unfinished stubbing detected here:
-> at mk.finki.ukim.milenichinja.ServiceTests.AdoptionServiceFilterTests.init(AdoptionServiceFilterTests.java:87)
E.g. thenReturn() may be missing. Examples of correct stubbing:
when(mock.isOk()).thenReturn(true);
when(mock.isOk()).thenThrow(exception);
doThrow(exception).when(mock).someVoidMethod(); Hints:
missing thenReturn()
you are trying to stub a final method, which is not supported
you are stubbing the behaviour of another mock inside before 'thenReturn' instruction is completed
Any ideas how to solve this problem?
In the init method, you are stubbing findById on the mock instance this.petRepository to return a non-mock Optional, which is good. In your new test, you are trying to set a return value for isPresent, which you can't do because Optional is not a mock. If you want to override the behavior per-test, you'll need to stub findById to return an Optional of a different instance. Therefore, this is right, though it appears exactly as it does in init and consequently it can't tell you why your test is failing.
Mockito.when(this.petRepository.findById(0))
.thenReturn(java.util.Optional.of(pet));
Mockito works by creating a mock object that subclasses a class and overrides every method. The overridden method is what interacts with a static (ThreadLocal) infrastructure, allowing you to use when syntax. The important thing here is that when ignores its argument, and instead tries to mock the last interaction that you made with a mock. You can find out more in the SO questions How does mockito when() invocation work? and How do Mockito matchers work?.
When you see this call:
Mockito.when(this.petRepository.findById(0))
.thenReturn(java.util.Optional.of(pet));
Then it works as you've intended:
petRepository is a mock, findById is presumably an overridable method, Mockito records the fact that you've called it with the argument 0.
findById doesn't have any behavior stubbed yet, so it does its default, returning null.
when doesn't care that it just received null, because the null doesn't tell it anything about what methods were called to get the null. Instead it looks back at its most recent record (findById(0)) and returns an object with the thenVerb methods you expect.
You call thenReturn, so Mockito sets up petRepository to return the Optional instance you created and passed in.
But when you try this call:
Mockito.when(this.petRepository.findById(0).isPresent()).thenReturn(true);
Then the most recent interaction isn't isPresent, it's findById, so Mockito assumes you want findById(0) to thenReturn(true) and throws WrongTypeOfReturnValue. Optional is not a mock, so interacting with it doesn't let Mockito record its interaction or replay your behavior. For what it's worth, I also wouldn't advise mocking it: Optional is a final class, and though Mockito has recently added some support for mocking final types, Optional is simple and straightforward enough that it makes more sense to just return the Optional instance you want rather than trying to mock it.
With all that said, your code looks right; as long as PetRepository is an interface I don't see anything about the way your method looks or the way your mocks look that would cause this.petRepository.findById(0) to return an absent Optional. In fact, I don't even see where you would create an absent Optional for it to return, so I can only guess that you are using more real objects in your test than you think you are.

isPresent() method returns false (in testing with Mockito) [duplicate]

I am trying to test the following method with JUnit tests, using Mockito:
#Override public List<Adoption> search(String username, Integer id) {
List<Adoption> emptySearchResult = new ArrayList<>();
if(id != null && !username.equals("") ) {
if(!this.petRepository.findById(id).isPresent()){
return emptySearchResult;
}
if(!this.appUserRepository.findByUsername(username).isPresent()){
return emptySearchResult;
}
Pet pet = this.petRepository.findById(id).orElseThrow( () -> new PetNotFoundException(id));
AppUser user = this.appUserRepository.findByUsername(username).orElseThrow( () -> new UsernameNotFoundException(username));
return this.adoptionRepository.findAllByUserAndPet(user, pet);
}
else if(id != null && username.equals("")){
if(!this.petRepository.findById(id).isPresent()){
return emptySearchResult;
}
Pet pet = this.petRepository.findById(id).orElseThrow( () -> new PetNotFoundException(id));
return this.adoptionRepository.findAllByPet(pet);
}
else if(id == null && !username.equals("")) {
if(!this.appUserRepository.findByUsername(username).isPresent()){
return emptySearchResult;
}
AppUser user = this.appUserRepository.findByUsername(username).orElseThrow( () -> new UsernameNotFoundException(username));
return this.adoptionRepository.findAllByUser(user);
}
else {
return this.adoptionRepository.findAll();
}
}
However, I run into a problem with the following part:
if(!this.petRepository.findById(id).isPresent())
Even though I have mocked this.petRepository.findById(id), for some reason isPresent() is returning false. This is my initialization for the tests:
#Mock
private AdoptionRepository adoptionRepository;
#Mock
private PetRepository petRepository;
#Mock
private AppUserRepository appUserRepository;
private AdoptionServiceImpl service;
private Adoption adoption1;
private Adoption adoption2;
private Adoption adoption3;
private AppUser user;
private AppUser user2;
private Pet pet;
private Pet petAlteadyAdopted;
List<Adoption> allAdoptions = new ArrayList<>();
List<Adoption> userFilteredAdoptions = new ArrayList<>();
List<Adoption> petFilteredAdoptions = new ArrayList<>();
#Before
public void init() {
MockitoAnnotations.initMocks(this);
user = new AppUser("username","name","lastname","email#gmail.com","pass",ZonedDateTime.now(), Role.ROLE_USER, City.Skopje);
user2 = new AppUser("username1","name","lastname","email#gmail.com","pass",ZonedDateTime.now(), Role.ROLE_USER, City.Skopje);
Center center = new Center("a", City.Bitola,"url");
pet = new Pet("p", Type.DOG,"b", Gender.FEMALE,"d",center, ZonedDateTime.now(),"url",null,false,ZonedDateTime.now());
petAlteadyAdopted = new Pet("p", Type.DOG,"b", Gender.FEMALE,"d",center, ZonedDateTime.now(),"url",null,true,ZonedDateTime.now());
pet.setId(0);
petAlteadyAdopted.setId(1);
adoption1 = new Adoption(ZonedDateTime.now(),ZonedDateTime.now(),Status.ACTIVE,user,pet);
adoption2 = new Adoption(ZonedDateTime.now(),ZonedDateTime.now(),Status.CLOSED,user,pet);
adoption3 = new Adoption(ZonedDateTime.now(),ZonedDateTime.now(),Status.CLOSED,user2,new Pet());
allAdoptions.add(adoption1);
allAdoptions.add(adoption2);
allAdoptions.add(adoption3);
petFilteredAdoptions.add(adoption2);
petFilteredAdoptions.add(adoption1);
userFilteredAdoptions.add(adoption2);
userFilteredAdoptions.add(adoption1);
Mockito.when(this.adoptionRepository.findById(0)).thenReturn(java.util.Optional.of(adoption1));
Mockito.when(this.adoptionRepository.findById(1)).thenReturn(java.util.Optional.of(adoption2));
Mockito.when(this.petRepository.findById(0)).thenReturn(java.util.Optional.of(pet));
Mockito.when(this.petRepository.findById(1)).thenReturn(java.util.Optional.of(petAlteadyAdopted));
Mockito.when(this.appUserRepository.findByUsername("username")).thenReturn(java.util.Optional.of(user));
Mockito.when(this.appUserRepository.findByUsername("username1")).thenReturn(java.util.Optional.of(user2));
Mockito.when(this.adoptionRepository.findAll()).thenReturn(allAdoptions);
Mockito.when(this.adoptionRepository.findAllByPet(pet)).thenReturn(petFilteredAdoptions);
Mockito.when(this.adoptionRepository.findAllByUser(user)).thenReturn(userFilteredAdoptions);
Mockito.when(this.adoptionRepository.findAllByUserAndPet(user,pet)).thenReturn(userFilteredAdoptions);
Mockito.when(this.adoptionRepository.save(Mockito.any(Adoption.class))).thenReturn(adoption1);
this.service = Mockito.spy(new AdoptionServiceImpl(this.adoptionRepository, this.petRepository,this.appUserRepository));
}
As a result, the following test fails, even though it should pass:
#Test
public void searchTest2() {
List<Adoption> adoptionList = this.service.search("",0);
Assert.assertEquals(petFilteredAdoptions,adoptionList);
}
In order to solve this I tried mocking the isPresent() method:
Mockito.when(this.petRepository.findById(0).isPresent()).thenReturn(true);
But I'm getting the following exception:
org.mockito.exceptions.misusing.WrongTypeOfReturnValue:
Boolean cannot be returned by findById() findById() should return
Optional***
If you're unsure why you're getting above error read on. Due to the
nature of the syntax above problem might occur because:
This exception might occur in wrongly written multi-threaded tests. Please refer to Mockito FAQ on limitations of concurrency
testing.
A spy is stubbed using when(spy.foo()).then() syntax. It is safer to stub spies -
with doReturn|Throw() family of methods. More in javadocs for Mockito.spy() method.
I also tried the following variation:
Mockito.doReturn(true).when(this.petRepository.findById(0)).isPresent();
But then I got the following exception:
org.mockito.exceptions.misusing.UnfinishedStubbingException:
Unfinished stubbing detected here:
-> at mk.finki.ukim.milenichinja.ServiceTests.AdoptionServiceFilterTests.init(AdoptionServiceFilterTests.java:87)
E.g. thenReturn() may be missing. Examples of correct stubbing:
when(mock.isOk()).thenReturn(true);
when(mock.isOk()).thenThrow(exception);
doThrow(exception).when(mock).someVoidMethod(); Hints:
missing thenReturn()
you are trying to stub a final method, which is not supported
you are stubbing the behaviour of another mock inside before 'thenReturn' instruction is completed
Any ideas how to solve this problem?
In the init method, you are stubbing findById on the mock instance this.petRepository to return a non-mock Optional, which is good. In your new test, you are trying to set a return value for isPresent, which you can't do because Optional is not a mock. If you want to override the behavior per-test, you'll need to stub findById to return an Optional of a different instance. Therefore, this is right, though it appears exactly as it does in init and consequently it can't tell you why your test is failing.
Mockito.when(this.petRepository.findById(0))
.thenReturn(java.util.Optional.of(pet));
Mockito works by creating a mock object that subclasses a class and overrides every method. The overridden method is what interacts with a static (ThreadLocal) infrastructure, allowing you to use when syntax. The important thing here is that when ignores its argument, and instead tries to mock the last interaction that you made with a mock. You can find out more in the SO questions How does mockito when() invocation work? and How do Mockito matchers work?.
When you see this call:
Mockito.when(this.petRepository.findById(0))
.thenReturn(java.util.Optional.of(pet));
Then it works as you've intended:
petRepository is a mock, findById is presumably an overridable method, Mockito records the fact that you've called it with the argument 0.
findById doesn't have any behavior stubbed yet, so it does its default, returning null.
when doesn't care that it just received null, because the null doesn't tell it anything about what methods were called to get the null. Instead it looks back at its most recent record (findById(0)) and returns an object with the thenVerb methods you expect.
You call thenReturn, so Mockito sets up petRepository to return the Optional instance you created and passed in.
But when you try this call:
Mockito.when(this.petRepository.findById(0).isPresent()).thenReturn(true);
Then the most recent interaction isn't isPresent, it's findById, so Mockito assumes you want findById(0) to thenReturn(true) and throws WrongTypeOfReturnValue. Optional is not a mock, so interacting with it doesn't let Mockito record its interaction or replay your behavior. For what it's worth, I also wouldn't advise mocking it: Optional is a final class, and though Mockito has recently added some support for mocking final types, Optional is simple and straightforward enough that it makes more sense to just return the Optional instance you want rather than trying to mock it.
With all that said, your code looks right; as long as PetRepository is an interface I don't see anything about the way your method looks or the way your mocks look that would cause this.petRepository.findById(0) to return an absent Optional. In fact, I don't even see where you would create an absent Optional for it to return, so I can only guess that you are using more real objects in your test than you think you are.

Mockito: verify that a method was not called with specific parameter type

I wanted to test with Mockito that a method was not called with a specific parameter type with this simplified test:
#Test
public void testEm() {
EntityManager emMock = Mockito.mock(EntityManager.class);
emMock.persist("test");
Mockito.verify(emMock, Mockito.never()).persist(Matchers.any(Integer.class));
}
Surprisingly this test failed with the following output:
org.mockito.exceptions.verification.NeverWantedButInvoked:
entityManager.persist(<any>);
Never wanted here:
-> at com.sg.EmTest.testEm(EmTest.java:21)
But invoked here:
-> at com.sg.EmTest.testEm(EmTest.java:19)
I expected this test to fail only when the persist method is called with an Integer parameter, but it fails with String as well.
Why doesn't it work and how could I test it?
Thank You.
The persist() method takes an argument as Object and when you select any(Integer.class) will be converted to any object, so it will fail because you call it using String.
The best method here to specify the argument using eq(), like this
Mockito.verify(emMock, Mockito.never()).persist(Matchers.eq(Integer.valueOf(1)));
Or use ArgumentCaptor to capture the arguments and assert them
#Test
public void testEm() {
// Arrange
EntityManager emMock = Mockito.mock(EntityManager.class);
ArgumentCaptor<Object> captor = ArgumentCaptor.forClass(Object.class);
// Act
emMock.persist("test");
// Assert
verify(emMock).persit(captor.catpure());
Object val = captor.getValue();
Assert....
}
Oracle doc#persist()
You can try to use not matcher http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/Matchers.html#not(org.hamcrest.Matcher)
Matchers.not(Matchers.any(Integer.class))

Mocking class is returning null instead of data

In my Junit test, I'm doing the following in my Junit test :
#Before
public void setUp() throws Exception {
reportQueryParams = ReportQueryParams.builder()
.id("07")
.build();
}
#Test
public void tabSerializerTest() {
MetricsSerializer mockMonth = mock(MetricsSerializer.class);
when(mockMonth.getCurrentMonth()).thenReturn("July");
String tabSeparated = mockMonth.serializeMetrics(reportQueryParams);
String expected = new StringBuilder().append("074")
.append("\t")
.append("July")
.toString();
assertEquals(expected, tabSeparated);
}
The function which I am testing:
public String serializeMetrics(final ReportQueryParams reportQueryParams) {
stringJoiner = new StringJoiner("\t");
addValueFromString(reportQueryParams.getId());
addValueFromString(getCurrentMonth());
return stringJoiner.toString();
}
public String getCurrentMonth() {
DateFormat monthFormat = new SimpleDateFormat("MMMMM");
return monthFormat.format(new Date());
}
private void addValueFromString(final String value) {
stringJoiner.add(value);
}
My ReportQueryParams class:
public class ReportQueryParams {
private String id;
}
I am getting "null" in the actual data returned and hence the test is failing. How can I fix this?
Don't mock the object you test.What you have written is "create a mock object that returns July for current month". But this mock object doesn't have real behaviour and the other methods return null.
When you test a class you mock the objects required by the class (in order to insulate behaviour) and not the actual class. Here you can create a new MetricsSerializer (by using new :) and call it's method serializeMethod and compare against the current date (instead of July).
The way you have written the class might not be the best testable way though ;)
Your problem is that you are mocking the class, then testing the mock object, rather than testing a "real" object. I can think of two possible solutions.
Use a Mockito Spy instead of a mock. This is like a mock, but it's a real object, and the methods all have their normal behaviour, instead of "no behaviour" by default. You can stub the getCurrentMonth method of your spy, to make it return what you want.
Since the real cause of your problem is the call to new Date(), you could use a time helper, instead of calling new Date() directly in your getCurrentMonth() method. I have described this technique in detail in my answer to this question

Mocking ColumnDefinitions.Definition does return mock, but is behaves like null in the tested code

I have following code preparing mocks to test my service using Cassandra (I need to mock com.datastax.driver.core.ColumnDefinitions.Definition) :
#RunWith(PowerMockRunner.class)
public class TestMyClass{
private MyClass target;
#Before
public void setUp() throws Exception {
ColumnDefinitions mockColumnDefinitions=Mockito.mock(ColumnDefinitions.class);
Mockito.when(mockRow.getColumnDefinitions()).thenReturn(mockColumnDefinitions);
target= new MyClass();
Definition mockDef = Mockito.mock(Definition.class);
List<Definition> defList = new ArrayList<Definition>();
defList.add(mockDef);
Iterator mockIterator = Mockito.mock(Iterator.class);
Mockito.when(mockColumnDefinitions.iterator()).thenReturn(mockIterator);
Mockito.when(mockIterator.hasNext()).thenReturn(true, false);
Mockito.when(mockIterator.next()).thenReturn(mockDef);
Mockito.when(mockDef.getName()).thenReturn(NAME);
}
#Test
public void testMyMethod() throws Exception {
target.MyMethod();
}
}
Test execution goes fine this place, and I have this type of code in different places, so it should work.
Inside the service I am testing I have following code:
ColumnDefinitions colDef = row.getColumnDefinitions();
Iterator<Definition> defIterator = colDef.iterator();
while (defIterator.hasNext()) {
Definition def = defIterator.next();
String columnName = def.getName();
}
When I debug this code, I see, that both colDef and defIterator are mocked successfully. I see something like that in debug variables area:
Mock for Iterator, hashCode: 430126690
But after defIterator.next() invocation I see that though def is an object and not null, it doesn't show hashcode like for Iterator, instead I see this:
com.sun.jdi.InvocationException occurred invoking method.
And after invoking this string:
String columnName = def.getName();
I immediately get NullPointerException like if def is null.
What am I doing wrong?
Thanks.
EDIT 1 ________________________________________________________________________
I also tried to use PowerMockito with the same methods instead, the result is the same.
EDIT 2 ________________________________________________________________________
I added the whole test method code.
It is been a while since this question was created. I have faced this same problem few days ago and I have solved it in the following manner (I hope my proposed solution helps someone in the future):
First of all, I want to clarify that ColumnDefinition.Definition class is a public static nested class that has four private final fields and only has one constructor: Definition (String keyspace, String table, String name and DataType type) (for more details please refer to the ColumnDefinitions.Definition javadoc and ColumnDefinitions source code). Therefore this nested class could not be mocked by Mockito nor Powermock because of its final fields.
SOLUTION:
I had to create a real object, not a mocked one of the class ColumnDefinition.Definition using reflection, so you can initialise the mockDef object as follows:
Constructor<Definition> constructor = (Constructor<Definition>) Definition.class.getDeclaredConstructors()[0]; // as Definition only has one constructor, 0 will be passed as index
constructor.setAccessible(true);
Definition mockDef = constructor.newInstance("keyspace", "table", "name", null);
replacing this line of code in your snippet:
Definition mockDef = Mockito.mock(Definition.class);
Then the NullPointerException will never be thrown again when executing this line of code:
String columnName = def.getName();

Categories