Mocked method wraps exception in collection rather than throwing exception - java

I have a test using jmockit's result = new Object[] {...} that is failing. The jmockit version is 1.34. The test should throw an exception but instead jmockit is returning a collection with the exception in it. Here is an example:
public class ServiceTest {
public class Service {
private Set<String> saved;
public Service() {
saved = new HashSet<>();
saved.add("one");
saved.add("two");
}
public Set<String> readAll() {
return Collections.unmodifiableSet(saved);
}
}
#Test(expected = RuntimeException.class)
public void testReadAll(#Mocked Service service) {
new Expectations() {{
service.readAll(); times = 1; result = new RuntimeException();
}};
service.readAll();
}
#Test
public void testReadAllWithArray(#Mocked Service service) {
new Expectations() {{
service.readAll(); times = 1; result = new Object[]{new RuntimeException()};
}};
Set set = service.readAll();
assertThat(set.iterator().next(), instanceOf(RuntimeException.class));
}
}
testReadAllWithArray shows that the object returned by readAll is a set with the exception in it.
Is this a bug or is there any workaround?

Upgrade from jmockit 1.34 to the latest version.

Related

Mocked Object not returning expected value

I'm unit testing my dao. I create a list, I add an object to my list and I tell mockito when my method is called, to return my list with a single object. However, when I look at what's returned from my dao method, it's an empty list. I'm not sure what I'm missing.
#InjectMocks
private Dao dao;
#Mock
private JdbcTemplate jdbcTemp;
#Test
public void testGetData() {
List<MyObj> list = new ArrayList<>();
MyObj myObj = new MyObj();
myObj.setMethod("method val");
list.add(myobj);
Mockito.when(jdbcTemp.query(anyString(), Mockito.any(PreparedStatementSetter.class),
Mockito.any(Dao.MyRowMapper.class))).thenReturn(list);
List<MyObj> res = dao.getData(param1, param2); // this is empty, instead of having a value of 1
Assertions.assertThat(res).isNotNull();
}
My Dao class:
public List<MyObj> getData(String arg1, String arg2) {
List<MyObj> list = new ArrayList<MyObj>();
try {
list.addAll(jdbcTemp.query(query, new PreparedStatementSetter() {
public void setValues(PreparedStatement pstmt) throws SQLException {
pstmt.setString(PARAM_ONE, arg1);
pstmt.setString(PARAM_TWO, arg2);
}
}, new MyRowMapper()));
} catch (Exception exp) {
}
return list;
}
I actually made a mistake in describing the problem.
I had two jdbcTemplates in my dao.
So the way I resolved it is to use a #Qualifier("jdbcTemplate") when creating a mock jdbctemplate

Mockito showing 0 interactions with mock

Here is my code:
public class S3Dao {
private final AmazonS3Client amazonS3Client;
static final String BUCKET_NAME = "myBucket";
public S3Dao(final AmazonS3Client amazonS3Client) {
this.amazonS3Client = amazonS3Client;
}
public void put(ModelObject modelObject, String playlistId) {
this.amazonS3Client.putObject(BUCKET_NAME, playlistId, new Gson().toJson(modelObject));
}
}
And my test code:
#ExtendWith(MockitoExtension.class)
public class S3DaoTest {
private S3Dao s3Dao;
#Mock
private AmazonS3Client s3Client;
#BeforeEach
public void beforeEach() {
this.s3Dao = new S3Dao(this.s3Client);
}
#Test
public void putTest() {
ModelObject obj = new ModelObject("name", new ArrayList<>());
String json = new Gson().toJson(obj);
verify(s3Client).putObject(S3Dao.BUCKET_NAME, "playlistId", json);
this.s3Dao.put(obj, "playlistId");
}
}
The resulting error is
Wanted but not invoked:
s3Client.putObject(
"myBucket",
"playlistId",
"{"name":"name","children":[]}"
);
-> at com.amazon.amazon.live.destination.playlist.dao.S3DaoTest.putTest(S3DaoTest.java:34)
Actually, there were zero interactions with this mock.
Indeed, removing the verify causes the test to pass without issue. Why isn't this working?
Move the verify after the method call
#Test
public void putTest() {
ModelObject obj = new ModelObject("name", new ArrayList<>());
String json = new Gson().toJson(obj);
this.s3Dao.put(obj, "playlistId");
verify(s3Client).putObject(S3Dao.BUCKET_NAME, "playlistId", json);
}

org.mockito.exceptions.misusing.WrongTypeOfReturnValue: ArrayList cannot be returned by getDetails()

here is code
public class TodoBusinessImpl {
BusinessManager businessManager;
public TodoBusinessImpl(BusinessManager businessManager) {
this.businessManager = businessManager;
}
public List<String> retrieveTodosRelatedToSpring(String user) {
List<String> filteredTodos = new ArrayList<String>();
Map<String, String> test = businessManager.getDetails();
return filteredTodos;
}
}
what is wrong with that? what i am doing wrong
public class MockitoTest {
private BusinessManager businessManager;
#Before
public void setUp() {
businessManager = Mockito.mock(BusinessManager.class);
}
#Test
public void retrieveTodosRelatedToSpringTest() {
TodoBusinessImpl todoBusinessImpl = new TodoBusinessImpl(businessManager);
Mockito.when(todoBusinessImpl.retrieveTodosRelatedToSpring("test"))
.thenReturn(Arrays.asList("test"));
}
}
This is the test class. Getting exception that org.mockito.exceptions.misusing.WrongTypeOfReturnValue:
ArrayList cannot be returned by getDetails()
You have to call the method that you're testing not mock it's behavior "not tell it what to do when it's called".
Instead of:
Mockito.when(todoBusinessImpl.retrieveTodosRelatedToSpring("test")).thenReturn(Arrays.asList("test"));
You should do this:
List<String> list = todoBusinessImpl.retrieveTodosRelatedToSpring("test");
// print list or assert it's content to make sure you're getting the right response

is there Mockito eq matcher for varargs array?

I have a problem when trying to match an array that is passed as a parameter to a method that receives a varargs array.
The anyVararg() matcher that is mentioned in other questions/answers doesn't work for me because I want to make sure the provided array is the one I need.
I reduced the problem to this example which is easier to understand and abstracts the problem (my real issue is production code and has busines logic so it would be confusing for the purpose of this question):
#RunWith(MockitoJUnitRunner.class)
public class UnitTest {
private Object[] objectArray;
private List<Object> expected;
private TestTarget target;
#Before
public void setUp() {
objectArray = new Object[]{ new Object() };
expected = Arrays.asList(new Object(), new Object());
target = Mockito.spy(new TestTarget());
}
#Test
public void testMakeList() { // this pass as eq works well with normal array
doReturn(expected).when(target).toList(Mockito.eq(objectArray));
Assert.assertEquals(expected, target.makeList(objectArray));
}
#Test
public void testMakeList1() { // this one fails as eq is not working with varargs
doReturn(expected).when(target).toList1(Mockito.eq(objectArray));
Assert.assertEquals(expected, target.makeList1(objectArray));
}
#Test
public void testMakeListWithAryEq() { // fails, aryEq is not working with varargs
doReturn(expected).when(target).toList1(AdditionalMatchers.aryEq(objectArray));
Assert.assertEquals(expected, target.makeList1(objectArray));
}
private class TestTarget {
public List<Object> makeList(Object[] objects) {
return toList(objects);
}
public List<Object> makeList1(Object[] objects) {
return toList1(objects);
}
protected List<Object> toList(Object[] objs) {
return null; // Not implemented "Intentionally"
}
protected List<Object> toList1(Object... objs) {
return null; // Not implemented "Intentionally"
}
}
}
When I run the test cases in the class, the first test case will pass but not the other two, neither using eq nor using aryEq. Showing the following trace:
java.lang.AssertionError: expected:<[java.lang.Object#56d5e457, java.lang.Object#7482384a]> but was:<null>
at org.junit.Assert.fail(Assert.java:88)
at org.junit.Assert.failNotEquals(Assert.java:743)
at org.junit.Assert.assertEquals(Assert.java:118)
at org.junit.Assert.assertEquals(Assert.java:144)
...
This happens because the eq matcher is not working with varargs arrays, is there any alternative to the eq matcher for this use case?
Ok, I think the answer here requires a custom built matcher, which can be implemented in your unit test as so:
private class MyVarargMatcher extends ArgumentMatcher<Object[]> implements VarargMatcher {
private Object[] expectedValues;
MyVarargMatcher(Object... expectedValues) {
this.expectedValues = expectedValues;
}
#Override
public boolean matches(Object varargArgument) {
return new EqualsBuilder()
.append(expectedValues, varargArgument)
.isEquals();
}
}
Then, in testMakeList1() change the first line to this:
Mockito.doReturn(expected).when(target).toList1(Mockito.argThat(new MyVarargMatcher(objectArray)));
Sources:
How to properly match varargs in Mockito
http://maciejmadej.blogspot.com/2011/11/capturing-varargs-argument-using-custom.html
This is no problem with matching varargs. The only limitation is that you have to specify each individual array entry as a matched argument. I have updated your code below to show what I mean. I created a second objectArray2 to make the point clearer. All tests pass:
#RunWith(MockitoJUnitRunner.class)
public class UnitTest {
private Object[] objectArray;
private Object[] objectArray2;
private List<Object> expected;
private TestTarget target;
private Object obj,obj2;
#Before
public void setUp() {
obj = new Object();
obj2 = new Object();
objectArray = new Object[]{ obj };
objectArray2 = new Object[]{ obj, obj2 };
expected = Arrays.asList(new Object(), new Object());
target = Mockito.spy(new TestTarget());
}
#Test
public void testMakeList() { // this pass as eq works well with normal array
doReturn(expected).when(target).toList(Mockito.eq(objectArray));
Assert.assertEquals(expected, target.makeList(objectArray));
}
#Test
public void testMakeList1() { // since objectArray has one entry you need to add one matching argument
doReturn(expected).when(target).toList1(Mockito.eq(obj));
Assert.assertEquals(expected, target.makeList1(objectArray));
}
#Test
public void testMakeListWithAryEq() { // since objectArray2 has two entries you need to add two matching arguments
doReturn(expected).when(target).toList1(Mockito.eq(obj),Mockito.eq(obj2));
Assert.assertEquals(expected, target.makeList1(objectArray2));
}
private class TestTarget {
public List<Object> makeList(Object[] objects) {
return toList(objects);
}
public List<Object> makeList1(Object[] objects) {
return toList1(objects);
}
protected List<Object> toList(Object[] objs) {
return null; // Not implemented "Intentionally"
}
protected List<Object> toList1(Object... objs) {
return null; // Not implemented "Intentionally"
}
}
}

mockito stubbing returns null

I am using mockito as mocking framework. I have a scenerio here, my when(abc.method()).thenReturn(value) does not return value, instead it returns null.
Here is how my class and test looks like.
public class foo(){
public boolean method(String userName) throws Exception {
ClassA request = new ClassA();
request.setAbc(userName);
ClassB response = new ClassB();
try {
response = stub.callingmethod(request);
} catch (Exception e) {
}
boolean returnVal = response.isXXX();
return returnVal;
}
Now follwoing is the test
#Test
public void testmethod() throws Exception{
//arrange
String userName = "UserName";
ClassA request = new ClassA();
ClassB response = new ClassB();
response.setXXX(true);
when(stub.callingmethod(request)).thenReturn(response);
//act
boolean result = fooinstance.lockLogin(userName);
//assert
assertTrue(result);
}
stub is mocked using mockito i.e using #Mock. The test throws NullPointerException in class foo near boolean retrunVal = response.isXXX();
the argument matcher for stub.callingmethod(request).thenReturn(response) is comparing for reference equality. You want a more loose matcher, like this I think:
stub.callingmethod(isA(ClassA.class)).thenReturn(response);
Ensure that your ClassA implements its own equals and that it is correctly implemented.

Categories

Resources