0

Given: Java 8

Mockito 4.3

Junit 4.11

Here my java code:

public interface ClientListener {

    void addClientStatusListener(StatusListener statusListener);
}


@FunctionalInterface
public interface StatusListener {

    void statusChange(ClientStatus clientStatus);
}



public class MyIoClientBuilder {

    public MyIoClientBuilder subscribeProcessed(MyInterface myInterface) {
        // Some logic here
        return this;
    }

    public MyIoClientBuilder build() {
        // some logic
        return this;
    }

}


public interface MyInterface {

    public void myInnerMethod(String arg);
}


import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

public class MyIoClient {

    public MyIoClient(ClientListener clientListener) {
        clientListener.addClientStatusListener(new StatusListener() {
            @Override
            public void statusChange(ClientStatus clientStatus) {
                if (clientStatus.equals(ClientStatus.AUTHORIZED)) {
                    new MyIoClientBuilder()
                            .subscribeProcessed(new MyInterface() {
                                @Override
                                public void myInnerMethod(String jsonString) {
                                    try {
                                        Person person = new ObjectMapper().readValue(jsonString, Person.class);
                                        System.out.println("person = " + person);
                                    } catch (JsonProcessingException e) {
                                        throw new RuntimeException(e);
                                    }
                                }
                            }).build();
                }
            }
        });
    }
}

I need to validate that if jsonString is invalid json then throw RuntimeException.

Here my unit test:

    import org.junit.Test;
    
    import static org.assertj.core.api.Assertions.assertThatThrownBy;
    import static org.mockito.Mockito.*;

    @Test
    public void shouldThrowRuntimeExceptionWhenJsonInvalid() {
        // Arrange
        ClientListener clientListenerSpy = spy(ClientListener.class);
        doAnswer(
                invocation -> {
                    StatusListener clientStatusListener = invocation.getArgument(0);
                    clientStatusListener.statusChange(ClientStatus.AUTHORIZED);
                    return null; // Void methods must return null in doAnswer()
                })
                .when(clientListenerSpy)
                .addClientStatusListener(any(StatusListener.class));

        // Assert
        assertThatThrownBy(() -> {
            new MyIoClient(clientListenerSpy);
        }).isInstanceOf(RuntimeException.class);
    }

As result in class MyIoClient successfully call method statusChange. OK.

But the method myInnerMethod does not call in anonymous inner class MyEmiter.

As result here error:

java.lang.AssertionError: 
Expecting code to raise a throwable.
1
  • What happens to the argument passed to subscribeProcessed? When is its myInnerMethod called (by your production code)? Commented May 11 at 17:09

1 Answer 1

2

The code you showed in your question lack an important call: the call to MyInterface.myInnerMethod. You subscribe the listener with the interface MyIoClientBuilder but you never call that method.

BTW I would simplify the test itself a bit for better readability by using an ArgumentCaptor to fetch the outer listener and then call the method of the outer listener explicitly there:

import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;

import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy;
import static org.mockito.Mockito.*;

class MyIoClientTest {

  @Test
  void throws_when_Json_invalid() {
    ClientListener clientListenerMock = mock();

    new MyIoClient(clientListenerMock);

    ArgumentCaptor<StatusListener> captor = ArgumentCaptor.forClass(StatusListener.class);
    verify(clientListenerMock).addClientStatusListener(captor.capture());

    StatusListener capturedListener = captor.getValue();

    assertThatThrownBy(() -> {
      capturedListener.statusChange(ClientStatus.AUTHORIZED);
    }).isInstanceOf(RuntimeException.class);
  }
}

(Nevertheless this test will still fail as your implementation or the test lacks code to trigger the inner listener that should actually throw the exception.)

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.