Printing statements in thenReturn of mockito - java

I am using Mockito to mock a certain class while writing my test cases.
Is there a way to print some statements before returning a value? Like:
when(x.callFunction(10).thenReturn(new String("Hello"));
The above statement works, however I am not able to do the following:
when(x.callFunction(10).thenReturn({
System.out.println("Mock called---going to return hello");
return new String("Hello");});

With thenAnswer you can execute additional actions every time the mocked method is invoked.
when(x.callFunction(10)).thenAnswer(new Answer<String>() {
public String answer(InvocationOnMock invocation) {
System.out.println("Mock called---going to return hello");
return "Hello";
}
});
See also thenAnswer Vs thenReturn.

If the object you're going to create is not final, then besides thenAnswer provided by #Roland Weisleder, you can just use an anonymous subclass with init block in thenReturn, like the following example code:
class FoobarFactory {
public Foobar buildFoobar() {
return null;
}
}
class Foobar {
private String name;
public Foobar(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
with mock code as:
#Test
public void testFoobar() throws Exception {
FoobarFactory foobarFactory = mock(FoobarFactory.class);
when(foobarFactory.buildFoobar()).thenReturn(new Foobar("somename") {
{
System.out.println("Creating mocked Foobar");
}
});
Foobar foobar = foobarFactory.buildFoobar();
assertThat(foobar.getName(), is("somename"));
}

I like the other answers, but given your latest comment:
I will be using thenReturn in my final code. This is more to test my testing code and check if my mocking function is being called or not!
I have another idea for you: do not return/print on that call; use thenThrow() instead!
The point is: print statements in the console are sometimes helpful; but they are easy to be overlooked. If the whole purpose is to be sure that a certain call happens on a certain mock; then just throw an exception instead of returning a value. As JUnit will give you direct and hard-to-ignore feedback on that; by failing the testcase.
You could even go one step further and put up #expected on that test - in that way you have a method to test this aspect automatically - if the mock isn't called; no exception; test will fail.

Related

How to mock a method with a return value if there is a void method inside this method

I am testing a class that has a testable method (the method itself below) with a return value.
Using Mockito I am having a problem. Problem with void method roomDao.updateData(outData);
public IEntity getData(SimBasket<DataEntity, SimRequest> request) {
Entity outData = converterData.convertNetToDatabase(request);
roomDao.updateData(outData);
return outData;
}
Here is my test code:
#Test
public void getData() {
simRepo = new SimRepo();
Mockito.when(simRepo.getData(request)).thenReturn(new Entity());
}
Error log:
org.mockito.exceptions.misusing.CannotStubVoidMethodWithReturnValue:
'updateData' is a void method and it cannot be stubbed with a return value!
Voids are usually stubbed with Throwables:
doThrow(exception).when(mock).someVoidMethod();
I don't seem to really understand how to fix this, since the void method is inside a method with a return value.
instead of new SimRepo() try mock it by using Mockito's mock method:
#Test
public void getData() {
SimRepo simRepo =Mockito.mock(SimRepo.class);
Mockito.when(simRepo.getData(request)).thenReturn(new Entity());
}
Update:
If you also want to count the number of times this mock method called use this:
// this will check if mock method getData() with parameter `request` called exactly 1 times or not.
Mockito.verify(simRepo, Mockito.times(1)).getData(request);

MockedObject and Real Object give different results

I have started learning JUNIT.
Here is what i am trying to achieve.
I have a class which checks if the inputString is part of secretKey;
public class StringChecker {
public boolean isEqual(String name)
{
boolean isEqual = false;
if(getSecretKey().contains(name))
{
isEqual = true;
}
return isEqual;
}
public String getSecretKey()
{
return "OSKAR";
}
}
My test class is this
public class RandomCheck {
#Test
public void isEqualTest()
{
StringChecker stringChecker = mock(StringChecker.class);
when(stringChecker.getSecretKey()).thenReturn("james");
//assertEquals(true, new StringChecker().isEqual("OSKAR")); <----this test case passes
assertEquals(true, stringChecker.isEqual("james"));
}
}
When i use Mocked object it does not give me the expected result, hence failing the test. But when i use a real object it gives me expected result and passes the test.
Am i missing anything? Like any annotation
A mockito mock is an object having the interface of the mocked class, but not its implementation. Your StringChecker is mocked, meaning there is no implementation code making calls from isEqual to getSecretKey as you assume.
You could use mockito spy, See this SO question:
Mockito.spy() is a recommended way of creating partial mocks. The reason is it guarantees real methods are called against correctly constructed object because you're responsible for constructing the object passed to spy() method.
ROOKIE MISTAKE
Here's the rookie mistake i did (mentioned by Arnold).
I mocked the StringChecker class but i did not provide any implementation for isEqual(String) method.
And because there was no implementation, i was getting the default value. In this case false (return type of method is boolean).
Solution
Using static method spy(). (Again mentioned by #Arnold).
So here is what my working code looks like.
#Test
public void isEqualTest()
{
StringChecker stringChecker = new StringChecker();
StringChecker spy = spy(stringChecker);
when(spy.getSecretKey()).thenReturn("james"); // providing implementation for the method
assertEquals(true, spy.isEqual("james"));
}
What i learnt from it.
Just by mocking an object does not get your things done if you intend to use methods of mocked object (In simple terms PROVIDE IMPLEMENTATION for methods of mocked objects).
TIP
If you want to see the default value returned by mocked object, just call the method of mocked object in sysout(without giving implementation).
Hope it will help someone like me.Peace
An alternative way without mocking and with additional test cases:
#Test
public void isEqualTest() {
StringChecker stringChecker = new StringChecker() {
#Override
public String getSecretKey() {
return "james";
}
};
assertTrue(stringChacker.isEqual("james"));
assertTrue(stringChacker.isEqual("jam"));
assertTrue(stringChacker.isEqual("mes"));
assertFalse(stringChacker.isEqual("oops"));
}
BTW, the isEqual() can be simplified to one line:
public boolean isEqual(String name) {
return getSecretKey().contains(name);
}

Mockito: using a method in "thenReturn" to return a mock doesn't work

I have encountered what I assume might be a bug with Mockito, but was wondering if anyone else can shed light as to why this test doesn't work.
Basically, I have two objects, like this:
public class FirstObject {
private SecondObject secondObject;
public SecondObject getSecondObject() { return secondObject; }
}
public class SecondObject {
private String name;
public String getName() { return name; }
}
The first object is mocked via annotation and the before method:
#Mock
FirstObject mockedFirstObject;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
The second object is mocked in a method:
public SecondObject setupMockedSecondObject() {
SecondObject secondObject = Mockito.mock(SecondObject.class);
Mockito.when(secondObject.getName()).thenReturn("MockObject");
return secondObject;
}
When thenReturn contains a direct call to this method to setup and obtain a mock of the second object, it fails:
#Test
public void notWorkingTest() {
Mockito.when(mockedFirstObject.getSecondObject()).thenReturn(setupMockedSecondObject());
Assert.assertEquals(mockedFirstObject.getSecondObject().getName(), "MockObject");
}
But, when the mock returned by the same method is assigned to a local variable, which is used in thenReturn, it works:
#Test
public void workingTest() {
SecondObject mockedSecondObject = setupMockedSecondObject();
Mockito.when(mockedFirstObject.getSecondObject()).thenReturn(mockedSecondObject);
Assert.assertEquals(mockedFirstObject.getSecondObject().getName(), "MockObject");
}
Are we doing something wrong or is this indeed a bug/limitation in Mockito? Is there a deliberate reason for this not working?
This is indeed a limitation of Mockito, and it is referenced in their FAQ:
Can I thenReturn() an inlined mock()?
Unfortunately you cannot do this:
when(m.foo()).thenReturn(mock(Foo.class));
// ^
The reason is that detecting unfinished stubbing wouldn't work if we allow above construct. We consider is as a 'trade off' of framework validation (see also previous FAQ entry). However you can slightly change the code to make it working:
//extract local variable and start smiling:
Foo foo = mock(Foo.class);
when(m.foo()).thenReturn(foo);
The workaround, as mentioned, is to store the desired returned value in a local variable, like you have done.
The way I understand it is that Mockito validates the usage you make of it every time you call its methods. When another method is called during an on-going stubbing process, you are breaking its validation process.
You can't use a method in thenReturn, but you can in thenAnswer
Your code will be called after the when condition will occur,
unlike any workaround based on thenReturn
Thus you could write:
#Test
public void nowWorkingTest() {
Mockito.when(mockedFirstObject.getSecondObject()).thenAnswer(new Answer<Map>() {
#Override
public Map answer(InvocationOnMock invocation) {
return setupMockedSecondObject();
}
});
Assert.assertEquals(mockedFirstObject.getSecondObject().getName(), "MockObject");
}
Let find another example here
#Test
public void testAuthenticate_ValidCredentials() throws FailedToAuthenticateException {
String username = "User1";
String password = "Password";
/*Configure Returning True with when...thenReturn configuration on mock Object - Q5*/
//Write your code here
assertTrue(authenticator.authenticateUser(username, password));
}

Mockito ArgumentMatcher saying Arguments are Different

I am using Mockito for Unit testing and I am using ArgumentMatcher to check if a particular field of an argument has a particular value.
I have a StatusMatcher class that extends ArgumentMatcher and checks whether an object of class MyClass has a particular value in status field. The way I am invoking this in the tests is:
verify(myDAO, times(1)).update(argThat(new StatusMatcher("SomeStatus")));
Here update is the method of the DAO that is getting called with some MyClass object. I want to see if it has the correct status or not. This is what I get:
Argument(s) are different! Wanted:
myDAO.update(
<Status matcher>
);
-> at com.foo.bar.MyTest.test1
Actual invocation has different arguments:
myDAO.update(
com.foo.bar.MyClass
);
Note that this is working perfectly for all the test cases except one test case. So I know the StatusMatcher etc. have been coded correctly. I am not sure what is different about the method where its getting this exception.
What I want to know is: under what conditions will the ArgumentMatcher throw such exception so I can find out what I am missing (It is not for me to paste the actual method codes)
Please tell me if the explanation is not clear enough, and I will try to improve it. Thanks for reading this far :)
EDIT: Here is the code for my StatusMatcher class
private class StatusMatcher extends ArgumentMatcher<MyClass> {
private String status;
public StatusMatcher(String hs) {
status = hs;
}
#Override
public boolean matches(Object argument) {
return status.equals(((MyClass)argument).getStatus());
}
}
Like you said, it fails because the arguments are different. Take a look at the test below and you'll see that the second test method will fail because the status in your MyClass instance is different from SomeStatus that you passed in the matcher.
public class MatcherTest {
class MyClass{
private String status;
MyClass(String status) {
this.status = status;
}
public String getStatus(){
return status;
}
}
class MyDao {
public void update(MyClass myClass){}
}
class StatusMatcher extends ArgumentMatcher<MyClass> {
private String status;
public StatusMatcher(String hs) {
status = hs;
}
#Override
public boolean matches(Object argument) {
return status.equals(((MyClass)argument).getStatus());
}
}
#Test
public void shouldMatchStatus(){
MyDao mock = mock(MyDao.class);
mock.update(new MyClass("expectedStatus"));
verify(mock, times(1)).update(argThat(new StatusMatcher("expectedStatus")));
}
#Test
public void shouldNotMatchStatus(){
MyDao mock = mock(MyDao.class);
mock.update(new MyClass("unexpectedStatus"));
/* THE BELLOW WILL FAIL BECAUSE ARGUMENTS ARE DIFFERENT */
verify(mock, times(1)).update(argThat(new StatusMatcher("expectedStatus")));
}
}
I could take a wild guess that you could be reusing variables, or have a static field, etc. But without seeing your test code, no one can tell.
Try to simplify the test / code under test. Do you really need to
mutate arguments and also verify stubbing? Both of those actions
might indicate a code smell. Relax the argument verification and
use some kind of any() matcher Perform validation of arguments in the
For others that are facing a similar issue here is how I fixed it.
The code below will throw the following error if you pass in a new instance of an object. All you have to do in this case is create a variable since it will not create a new reference in memory.
#Test
void shouldLogExceptionWithType() {
mongoDao = mock(MongoDao.class);
StepDetail stepDetail = StepDetail.builder()
.table("some table")
.batchType("Some batch type")
.build();
doCallRealMethod().when(mongoDao).logException(new Exception(), stepDetail.getBatchType().getName());
mongoDao.logException(new Exception(), stepDetail.getBatchType().getName());
verify(mongoDao, times(1)).logException(new Exception(), stepDetail.getBatchType().getName());
}
Code Fixed:
#Test
void shouldLogExceptionWithType() {
mongoDao = mock(MongoDao.class);
StepDetail stepDetail = StepDetail.builder()
.table("some table")
.batchType("Some batch type")
.build();
Exception exception = new Exception();
doCallRealMethod().when(mongoDao).logException(exception, stepDetail.getBatchType().getName());
mongoDao.logException(exception, stepDetail.getBatchType().getName());
verify(mongoDao, times(1)).logException(exception, stepDetail.getBatchType().getName());
}
I also faced this issue. Below is the error and its solution:
error: Argument(s) are different! Wanted:
tradeMaintenanceDao.updateTradesMaintData(.....
I used the following statement to resolve it:
verify(tradeMaintenanceDao, times(1))
.updateTradesMaintData(anyString(), anyList(), anyList(), anyString(), anyString());
The original cause was:
verify(tradeMaintenanceDao, times(1)).updateTradesMaintData(userName, tradeStatusList, tradeReasonList, notes, pendStatus);

Invoking a private method via JMockit to test result

Am using JMockit 1.1 and all I want to do is invoke a private method and test the return value. However, I am having trouble understanding exactly how to do this from the JMockit De-Encapsulation example.
The method I am trying to test is the private method in this class:
public class StringToTransaction {
private List<String> parseTransactionString(final String input) {
// .. processing
return resultList;
}
}
And my test code is below.
#Test
public void testParsingForCommas() {
final StringToTransaction tested = new StringToTransaction();
final List<String> expected = new ArrayList<String>();
// Add expected strings list here..
new Expectations() {
{
invoke(tested, "parseTransactionString", "blah blah");
returns(expected);
}
};
}
And the error I am getting is:
java.lang.IllegalStateException: Missing invocation to mocked type at
this point; please make sure such invocations appear only after the
declaration of a suitable mock field or parameter
Perhaps I have misunderstood the whole API here, because I don't think I want to mock the class.. just test the result of calling the private method.
I think you are making this too complicated. You should not be using the Expectations block at all. All you need to do is something like this:
#Test
public void testParsingForCommas() {
StringToTransaction tested = new StringToTransaction();
List<String> expected = new ArrayList<String>();
// Add expected strings list here..
List<String> actual = Deencapsulation.invoke(tested, "parseTransactionString", "blah blah");
assertEquals(expected, actual);
}
Basically, call a private method via Deencapsulation and test that the actual is equal to the expected. Just like you would if the method were public. No mocking is being done, so no Expectations block is needed.
At this point, I don't know if JMockit can or should be used for this. Testing my private method can be done with plain old reflection, although I started this exercise to learn about JMockit (and test my code). In case JMockit cannot be used for this, here is how I can use reflection instead.
#Test
public void testParsingForCommas() throws Exception {
StringToTransaction tested = new StringToTransaction();
ArrayList<String> expected = new ArrayList<>();
expected.add("Test");
Method declaredMethod =
tested.getClass().getDeclaredMethod("parseTransactionString",
String.class);
declaredMethod.setAccessible(true);
Object actual = declaredMethod.invoke(tested, "blah blah");
assertEquals(expected, actual);
}
The call to setAccessible(true) is important here or the invoke will blow up when calling a private method.
declaredMethod.setAccessible(true);
But you want to know what is really cool? If you don't call setAccessible(true), it will blow up with a java.lang.StackOverflowError! :)
As mocking private methods is not allowed in latest Jmockit. One can mock the APIs used inside that private method as a Workaround instead of mocking the private method.
This workaround can also be treated as a final solution.
Example:
Actual Class:
class A {
private int getId(String name){ //private method
return DAOManager.getDao().getId(name); //Call to non-private method can be mocked.
}
}
Test Class:
public class ATest{
#Before
public void setUp(){
new MockDAOManager();
}
//Mock APIs used by the private method `getId`.
public static class MockDAOManager extends MockUp<MockDAOManager>{
static mocked_user_id = 101;
#Mock
public DAOManager getDao() throws Exception{
return new DAOManager();
}
#Mock
public Integer getId(String name){
return mocked_user_id;
}
}
}
Note:
If you don't have such logic(private method calls to another non-private
method) then you may have to refactor your code, Otherwise this will
not work.
Here DAOManager.getDao().getId(name) is not a private API.
There may be a need to mock all APIs used by that private method.
start from 1.35(?) jmockit removed that helper method. for reasons that it is no longer useful (which I don't quite understand)
but yes, this utility is available somewhere else
org.springframework.test.util.ReflectionTestUtils
As mentioned by #Jeff Olson, you can also call the private methods of a bean by declaring them #Tested.
Here is an example:
// Java
#Tested
private YourServiceImplClass serviceImpl;
#Test
public void testPrivateMethod() {
List<String> expected = new ArrayList<String>();
// Add expected strings list here..
List<String> actual = Deencapsulation.invoke(serviceImpl, "yourPrivateMethod", "arguments");
assertEquals(expected, actual);
}
Why do you want to test the private method directly ? Most of the times API methods i.e. public interface methods are unit tested as private methods will be be indirectly tested as well along with them. You can put assert statements with expected values from private methods where you call them within the public methods. So if assert fails you are sure that there is some issue with the private method. So you need not test it separately.

Categories

Resources