Here is my test
#Test
#WithMockUser(authorities = "ADMIN")
void shouldCreateRestaurant_whenPost() throws Exception {
// when
mockMvc.perform(
post("/restaurant/admin/")
.contentType(MediaType.APPLICATION_JSON)
.content(this.objectMapper.writeValueAsString(RESTAURANT_CREATION_DOMINOS)));
// then
Mockito.verify(restaurantService, times(1)).create(RESTAURANT_CREATION_DOMINOS);
}
It fails because it compares object with =. First object RestaurantCreationDTO#5980fa73, second RestaurantCreationDTO#15a8cebd.
But how can I make sure that restaurantService is called with a valid argument?
You have two options:
First - If it is enough to check if the object in the service call is indeed a RestaurantCreationDTO:
Mockito.verify(restaurantService, times(1)).create(any(RestaurantCreationDTO.class));
Second - If you really want to check the object content in the service call
In your Test class
#Captor
ArgumentCaptor<RestaurantCreationDTO> restaurantCreationDtoCaptor;
In your Test method
Mockito.verify(restaurantService, times(1)).create(restaurantCreationDtoCaptor.capture());
assertThat(restaurantCreationDtoCaptor.getValue()).isEqual(RESTAURANT_CREATION_DOMINOS)
Related
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))
I was writing a Junit to test a scenario where an object changes its variables and saves it into the database 2 times. The argumentCaptor is invoked in save operation. The getAllValues() is returning two records. But both values are referenced to the same last capture record.
ImplimentationClass.java
...
myObj.setVariable(oneValue);
saveMyObj(myObj);
myObj.setVariable(otherValue);
saveMyObj(myObj);
...
saveMyObj(MyObject myObj){
repository.save(myObj);
}
ImplimentationClassTest.java
private ImplimentationClass underTest ;
#Mock
private Repository mockRepository;
#Before
public void setup(){
initMocks(this);
underTest = new ImplimentationClassTest();
}
#Test
public void test(){
ArgumentCaptor<MyObject> captor = ArgumentCaptor.forClass(MyObject.class);
MyObject obj = new MyObject(value);
underTest.implementedMethod(obj);
verify(mockRepository, times(2)).save(captor.capture());
assertEquals(oneValue, captor.getAllValues().get(0).getVariable()); //failing here -getting otherValue
assertEquals(otherValue, captor.getAllValues().get(1).getVariable());
}
Any idea how to capture same object multiple times?
The problem from your test originates from this piece of code.
myObj.setVariable(oneValue);
saveMyObj(myObj);
myObj.setVariable(otherValue);
saveMyObj(myObj);
Once you change the variable inside of myObj you change it for all references. Note that the ArgumentCaptor does not make a deep copy of myObj.
So you will end up with two references to myObj, which only has the latest state.
To avoid this you might want to pass a different instance to the second call.
Another alternative might be to use doAnswer instead and check the correctness of the paramter inside that method.
Check this answer for an example.
I want to test this class, so it will shows me that I call ws with right params:
class MyService {
public static boolean sendEmail(MyWebService ws) {
if (!ws.sendCustomEmail("me#example.com", "Subject", "Body")) {
throw new RuntimeException("can't do this");
}
// ... some more logic which can return false and should be tested
return true;
}
}
Is there a way to combine mockito spy and thenReturn? I like how spy will show actual methods calls and not just simple message about assertionFailed.
#Test
void myTest() {
MyService spyWs = Mockito.spy(MyWebService.class);
// code below is not working, but I wonder if there is some library
verify(spyWs, once())
.sendCustomEmail(
eq("me#example.com"),
eq("Subject"),
eq("here should be another body and test shou")
)
.thenReturn(true);
MyService::sendEmail(spyWs);
}
What I want as a result is error message showing me the difference between parameters that expected and actual like usual spy's:
Test failed:
sendCustomEmail(eq("me#example.com"), eq("Subject"), eq("here should be another body and test should show diff")) was never called
sendCustomEmail(eq("me#example.com"), eq("Subject"), eq("Body")) was called, but not expected
Expected:
I know I can do just stub and then test for exception, but thats will not show the difference in parameters
When using a Spy, use the doReturn().when() syntax. Also verify after the set-up:
MyService spyWs = Mockito.spy(MyWebService.class);
doReturn(true).when(spyWs).sendCustomEmail(any(), any(), any());
MyService::sendEmail(spyWs);
verify(spyWs, once())
.sendCustomEmail(
eq("me#example.com"),
eq("Subject"),
eq("here should be another body and test shou")
);
// assert that sendMail returned true;
Frankly i dont think you need to verify here, just a boolean assertion would be enough but thats up to you.
I have a JUnit test as:
#Spy
ParallelSender parallelSender = new ParallelSender();
#Test
public void send() {
// making some data...
parallelSender.send(someData);
// check that internal method has been called with Sender Task made from someData
verify(parallelSender).doSend(any(SenderTask.class));
}
I however like to examine that SenderTask contains all the fields exactly as I need them. Can I tell the spy to intercept the doSend call, store its parameters in some array and then continue to real method?
Use the ArgumentCaptor:
#Test
public void send() {
// making some data...
parallelSender.send(someData);
// Define the captor for class
ArgumentCaptor<SenderTask> captor =
ArgumentCaptor.forClass(SenderTask.class);
// Capture input while verifying
verify(parallelSender).doSend(captor.capture());
// Assert
SomeTask result = captor.getValue();
// assertions on result
}
You can use an ArgumentCaptor.
#Captor
ArgumentCaptor<SenderTask> captor;
// or ArgumentCaptor<SenderTask> captor =
// ArgumentCaptor.forClass(SenderTask.class);
#Test public void send() {
// ...
verify(parallelSender).doSend(captor.capture());
SenderTask captured = captor.getValue();
I rarely use argument captor because it's usually not necessary.
Just do this
#Test
public void send() {
//given
SomeData myInput = ...
SenderTask expectedOutput = new SenderTask();
expectedOutput.setSomeField(/*expected field value*/);
//when
parallelSender.send(myInput);
//then
verify(parallelSender).doSend(expectedOutput);
}
The idea behind is to check that "doSend" was called with an expected object.
Note: just make sure that you implemented equals/hash method in SenderTask - or it will not work
Note2: I would suggest avoiding using any() in your unit tests. Usually when your are unit-testing something - you want to be as much precise as possible. So use concrete objects during results verification.
Hopefully it helps
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.