Test coverage inside .onStatus block is not covering

Below is my repo class

public class RepoService {
    @Autowired
    private WebClient webClient;
    
    public DIResponse createIdentity(DICreateRequest diCreateRequest) {
            CreateReq createReq = diCreateRequestMapper.setRequest(diCreateRequest);
            DIResponse diResponse = null;
    
            UriComponents uriBuilder = UriComponentsBuilder
                    .fromUriString(url)
                    .build(false);
    
            DIResponse apiResponse = webClient
                    .post()
                    .uri(uriBuilder.toUriString())
                    .body(Mono.just(createReq), CreateReq.class) 
                    .retrieve()
                    .onStatus(HttpStatus::is4xxClientError, clientResponse -> clientResponse.bodyToMono(DIBadRequest.class).flatMap(errorResponse -> {
                        LOGGER.error(CLIENT_ERROR, "POST", clientResponse.statusCode(), errorResponse);
                        return Mono.error(new DataAccessException(ERROR_STATUS +clientResponse.statusCode()+ ERROR_DESC+ errorResponse.getDetail()));
                    }))
                    .bodyToMono(DIResponse.class)
                    .block();
    
    return apiResponse;
     }
    }

Below is my Mockito junit test case

@Mock
    private WebClient webClient;

    @Mock
    WebClient.RequestHeadersUriSpec requestHeadersUriSpecMock;
    @Mock
    WebClient.RequestBodyUriSpec requestBodyUriSpecMock;

    @Mock
    WebClient.RequestBodySpec requestBodySpecMock;

    @Mock
    WebClient.RequestHeadersSpec requestHeadersSpecMock;

    @Mock
    WebClient.ResponseSpec responseSpecMock;

@InjectMocks
    private RepoService repositoryService;

@Test
    void testCreateIdentity() throws IOException {
        

        DICreateRequest mockDICreateRequest = getMockDICreatReq();
        CreateReq createReq = createDI();
        DIResponse mockDIResponse = getDI();

when(diCreateRequestMapper.setRequest(mockDICreateRequest)).thenReturn(createReq);

when(webClient.post()).thenReturn(requestBodyUriSpecMock);
when(requestBodyUriSpecMock.uri((URI) any())).thenReturn(requestBodySpecMock);
when(requestBodySpecMock.body(any())).thenReturn(requestHeadersSpecMock);
when(requestHeadersSpecMock.retrieve()).thenReturn(responseSpecMock);
when(responseSpecMock.onStatus(any(), any())).thenReturn(responseSpecMock);
Mockito.when(responseSpecMock.bodyToMono(DIResponse.class)).thenReturn(Mono.just(mockDIResponse));

        DIResponse result = repositoryService.createIdentity(mockDICreateRequest);

        Assert.assertEquals(mockDIResponse.getId(), result.getId());
    }

How can I cover testcases inside the .onStatus()
.onStatus(HttpStatus::is4xxClientError, clientResponse -> clientResponse.bodyToMono(DIBadRequest.class).flatMap(errorResponse -> {
LOGGER.error(CLIENT_ERROR, “POST”, clientResponse.statusCode(), errorResponse);

You need to use a Mockito Answer to get access to the lambda and call it as the real implementation would. Here is a simplified example:

package com.example.so;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.stubbing.Answer;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.verify;

@ExtendWith(MockitoExtension.class)
public class TestEg {
    @Mock
    private Thing thing;
    @InjectMocks
    private ToTest toTest;
    @Test
    public void theTest() {
        doAnswer(new Answer() {
            @Override
            public Object answer(InvocationOnMock invocationOnMock) throws Throwable {
                Runnable lambda = invocationOnMock.getArgument(0);
                lambda.run();
                return null;
            }
        }).when(thing).onStatus(any());
        toTest.doIt();
        verify(thing).doSomething();
    }
}
interface Thing {
    public void onStatus(Runnable lambda);

    void doSomething();
}
class ToTest {
    private final Thing thing;

    public ToTest(Thing thing) {

        this.thing = thing;
    }
    public void doIt() {
        thing.onStatus(() -> {
            thing.doSomething();
        });
    }
}

Leave a Comment