0
votes

I would like to perform a junit test using Mockito on the toEntity function.

    @Component
    public class MyEntityTransform {
        public Function<MyDTO , MyEntity> toEntity = new Function<MyDTO , MyEntity >() {
            @Override
            public MyEntity apply(MyDTO record) {
                return new MyEntity();
            }
        };  
    }

Unfortunately the toEntity is NULL when I mock the class and I don't know how I can test it correctly.

@RunWith(MockitoJUnitRunner.class)
public class MyTest {

    @InjectMocks
    private MyService _classUnderTest;

    @Mock
    private MyEntityTransform  myEntityTransform 

    @Before
    public void setUp() {
      Mockito.when(this.myEntityTransform.toEntity.apply(Mockito.anyObject())).thenReturn(...);
    }   
}

When I RUN the JUNIT test, Mockito give me the error :

java.lang.NullPointerException org.mockito.exceptions.misusing.InvalidUseOfMatchersException: Misplaced argument matcher detected here:

-> at com.example.MyTest.setUp(MyTest.java:38)

You cannot use argument matchers outside of verification or stubbing. Examples of correct usage of argument matchers: when(mock.get(anyInt())).thenReturn(null); doThrow(new RuntimeException()).when(mock).someVoidMethod(anyObject()); verify(mock).someMethod(contains("foo"))

Also, this error might show up because you use argument matchers with methods that cannot be mocked. Following methods cannot be stubbed/verified: final/private/equals()/hashCode(). Mocking methods declared on non-public parent classes is not supported.

Do you have suggestions?

1
There is absolutely no reason to use mocking here. Mocking is used, when testing A, that uses B, to provide a fake B to A. Mocking what you're testing doesn't make sense.JB Nizet
I don't get it. If you want to test that Function why is Mockito involved?Sotirios Delimanolis
I am sorry, I want to use the function toEntity as a mock in another test.Geoff L.
Post a complete minimal example reproducing the problem.JB Nizet
Your difficulty to mock the class is because you violate the most important principle in OOP information hiding. Method apply() (as you posted it here) is just a getter for the toEntity property. Either the class MyEntityTransform is a DTO without any logic, that this woule be OK but then it should not be mocked. Or MyEntityTransform contais some business logic, then nobody else should access its properties (directly).Timothy Truckle

1 Answers

8
votes

You're using public fields, which is not a good idea. But anyway, what you want to mock is the function, not the instance of MyEntityTransform. So you would need something like

@InjectMocks
private MyService _classUnderTest;

@Mock // or @Spy
private MyEntityTransform myEntityTransform;

@Before
public void prepare() {
    myEntityTransform.toEntity = mock(Function.class);
}

But quite frankly, I wouldn't use a public field of type Function. Instead, I would use a public method:

public class MyEntityTransform {
    public MyEntity toEntity(MyDTO record) {
        return new MyEntity();   
    }
}

Then you can mock MyEntityTransform and make its toEntity method return what you want. And if you need to pass a Function doing what the method does, use a method reference:

collection.stream().map(myEntityTranform::toEntity)