How to Mock a Generic Parameter for a Unit Test in Java

How to mock a generic parameter for a unit test in Java?

You are passing wrong parameters to when. It may be a bit confusing, but there are two different usages of when method (actually those are two different methods):

  1. when(mockedObject.methodYouWantToMock(expectedParameter, orYourMatcher)).thenReturn(objectToReturn);
  2. doReturn(objectToReturn).when(mockedObject).methodYouWantToMock(expectedParameter, orYourMatcher);

Note: pay attention to input parameters of when method in both cases.

In your particular case you could do something like this:

doReturn(null).when(iGenericServiceMock).save(any(Theodore.class), any(AnotherClass.class));

This will fix your compilation issues. However the test will fail at runtime with org.mockito.exceptions.misusing.CannotStubVoidMethodWithReturnValue because you are trying to return something from a void method (null is not void). What you should do is :

doNothing().when(iGenericServiceMock).save(any(Theodore.class), any(AnotherClass.class));

Later you can check the interactions with your mock using verify method.

UPDATE:

Check your imports. You should use org.mockito.Matchers.any instead of org.hamcrest.Matchers.any.

Unable to mock a method with generic parameters

Mockito.any() is not applicable for the type Class in your case. Should be fine if you specify Mockito.any(Class.class) in your condition.

public class TestClass
{
public class MyClass
{
public <K, T> T test(String s, K obj, final Class<T> clazz)
{
return null;
}
}

@Test
public void test()
{
MyClass myClass = Mockito.mock(MyClass.class);

Mockito.when(myClass.test(Mockito.anyString(), Mockito.any(), Mockito.any(Class.class))).thenThrow(new IllegalArgumentException());

myClass.test(null, null, null);
}
}

Using Mockito to mock classes with generic parameters

I think you do need to cast it, but it shouldn't be too bad:

Foo<Bar> mockFoo = (Foo<Bar>) mock(Foo.class);
when(mockFoo.getValue()).thenReturn(new Bar());

Mockito mocking when() for two generic methods of different types

Mockito doesn't know which generics was specified in front of any() invocation and anyway it doesn't matter.

The parameters expected in the recording a mock behavior has to rely on :

  • value (in terms of equals()
  • or in terms of captor if equals() is not adequate
  • or any() if the value of the parameter in the mock invocation doesn't matter or is not known in the test fixture

These never have to rely on the generic specified on.

To have a good example, look at Mockito.anyCollectionOf(Class<T> clazz) or Mockito.anyMapOf(Class<K> keyClazz, Class<V> valueClazz).

These methods know the class passed but anyway, their specifications state :

This method don't do any type checks, it is only there to avoid
casting in your code. This might however change (type checks could be
added) in a future major release.

Generally what you want to check is that the method to mock was invoked with the expected parameter and not any parameter : so any() will never achieve it.

So trying to check only the generic type but accepting any values as parameters seems be an anti pattern mocking.

In your case, if equals() is not convenient for the matching in the when() recording, use Mockito captor with verify() and do the check after the execution of the mock.

How to mock a generic implementation of a protocol?

  1. The Store<Student> syntax has never been supported, but there has been a lot of talk on the Swift forum about it lately—it may be soon.

  2. There are many other Q/A's on Stack Overflow about not being able to use a protocol with an associated type like an existential—it's finally available but only in Xcode 13.3 (beta).

It seems to me that you want things constrained like this:

class MyClassToBeTested<BookStore: Store, StudentStore: Store>
where
BookStore.AnyData == Book,
StudentStore.AnyData == Student
{
let bookStore: BookStore
let studentStore: StudentStore

If not, the latest syntax, available starting in Xcode 13.3, is

class MyClassToBeTested<StudentStore: Store>
where StudentStore.AnyData == Student {
let bookStore: any Store
let studentStore: StudentStore

init(
bookStore: any Store,
studentStore: StudentStore
) {
self.bookStore = bookStore
self.studentStore = studentStore
}
}


Related Topics



Leave a reply



Submit