Mocking a ListState in Apache Flink 1.4

BlameMe :

I am writing some test code for a processElement function in Apache Flink 1.4:

public class ProcessFunctionClass {

    public void processElement(Tuple2<String, String> tuple2,  Context context, Collector<Tuple2<String, String>> collector) {

        // if the state is empty, start a timer
        if (listState.get().iterator().hasNext() == false)
            context.timerService().registerEventTimeTimer(1000);

        listState.add("someStringToBeStored");

        // ...
    }

}
public class ProcessFunctionClassTest {

    private ProcessFunctionClass processFunctionClass;

    @Mock
    private ListState<String> listState;

    @Before
    public void setUp() throws Exception {
        processFunctionClass = new ProcessFunctionClass();
    }

    @Test
    public void testProcessElement() {

        ListState mockListState = mock(ListState.class);
        Iterable mockIterable = mock(Iterable.class);
        Iterator mockIterator = mock(Iterator.class);
        MockitoAnnotations.initMocks(this);

        when(tDPListState.get()).thenReturn(mockIterable);
        when(tDPListState.get().iterator()).thenReturn(mockIterator);
        when(tDPListState.get().iterator().hasNext()).thenReturn(false);

        processFunctionClass.processElement(tuple2, context, collector);

        // verify(...)
    }
}

When I debug using my IDE, just before I step into the processElement() method, listState is not null and appears to have been mocked successfully, but as soon as I get to listState.get().iterator().hasNext(), listState is null and I get a NullPointerException. What am I doing wrong here?

Lesiak :

In ProcessFunctionClass you have a private listState variable. In your test you create a completely unrelated mockListState variable and set some expectations on it.

For your test to work, you must provide a way (constructor or setter) to set ProcessFunctionClass.listState to desired value (your mocked list state)

On top of that, MockitoAnnotations.initMocks(this); seems to do nothing in your example: you haven't shown us any fields annotated with @Mock or @InjectMocks

Update

You are misusing @Mock annotation. You should place it in the test class, not in class under test. When placed in the test class, after a call to initMocks, the filed will be initialized with a mock of an appropriate type.

What you should fo instead:

  • remove MockitoAnnotations.initMocks(this);, you are creating all the mocks manually.
  • add a constructor in ProcessFunctionClass
public ProcessFunctionClass(ListState<String> listState) {
    this.listState = listState
}
  • use this constructor in your test
var mockListState = mock(ListState.class);
var processFunctionClass = new ProcessFunctionClass();

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related