简体   繁体   中英

How do you write a java unit test of a class method that does not return a value?

I am a newbie to Java unit testing and need help writing a unit test that just needs to handle 2 paths of an "if" statement where the method has no return value.

public class Consumer extends KafkaConsumer {
    private final MessageService service;

    public Consumer(MessageService service) {
        this.service = service;
    }

    @Override
    protected void processRecords(ConsumerRecords<Long, String> records) {
        for (ConsumerRecord<Long, String> records) {
            if (record.value().startsWith("{")) {
                OldFormatMessageObject mo = new OldFormatMessageObject(record.value());
                service.processMessage(mo);
            } else if (record.value().startsWith("metadata")) {
                NewFormatMessageObject mo = new NewFormatMessageObject(record.value());
                service.processMessage(mo);
            }
        }
    }

What to test?

Strictly speaking, there are actually 3 paths in branching logic to test:

  1. if startsWith("{") then MessageService#processMessage(OldFormatMessageObject) is called.
  2. if startsWith("metadata") then MessageService#processMessage(NewFormatMessageObject) is called.
  3. otherwise nothing happens.

It would be nice if "iteration" logic is unit tested as well ( for loop).

How to test?

We have to verify, that correct method of MessageService is called.

For this, we can use MessageService mock, which will be injected to Consumer via constructor.

Using mockito [1], it might look like this:

...

@Mock
private MessageService messageServiceMock;

// Tested instance
private Consumer consumer;

@BeforeEach
public void beforeEach() {
    consumer = new Consumer(messageServiceMock);
}

@Test
public void newMessageFormatIsHandled() {
    // Given
    final String expectedValue = "my-expected-value";

    // When
    consumer.processRecords(testSingleConsumerRecords(expectedValue));

    // Then
    verify(messageServiceMock, times(1)).processMessage(new NewFormatMessageObject(expectedValue));
    // OR
    verify(messageServiceMock, times(1)).processMessage(isA(NewFormatMessageObject.class));
}

...

Note, that if MessageService has interface, you don't even need any mock framework, and provide "mocked" instance to your unit test cases, but mock framework makes tests quite more readable.


[1] https://site.mockito.org

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM