groovyspockstubspring-resttemplate

Stub Rest Client method calling RestTemplate with ParameterizedTypeReference for Testing Service


I have problem testing a service with Spock and Groovy. For this, I try to Stub a method of my client, that calls RestTemplate with ParameterizedTypeReference.

NOTE: Sorry for my bulky code!!!

Here my Configuration Class

MyMicroserviceClientConfiguration class

@Data
@Configuration
@ConfigurationProperties(prefix = "clients.my-microservice-client")
public class MyMicroserviceClientConfiguration {
    @NotBlank
    private String urlDocsByName;
    @NotBlank
    private String urlSend;
}

Here a Static Classes

Attachment class

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class Attachment {
    private String idContent;
    private String name;
    private byte[] bytes;
}

AttachmentList class

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class AttachmentList {
    private List<Attachment> attachments;
}

Here my Client Class

MyMicroserviceClientImpl class

public class MyMicroserviceClientImpl implements MyMicroserviceClient {

    private final MyMicroserviceClientConfiguration myMicroserviceClientConfiguration;
    private final RestTemplate restTemplate;

    @Override
    public  AttachmentList getDocsByName(String idContent, String name) {
        Map<String, String> uriVars = new HashMap<>();
        uriVars.put("idContent", idContent);

        UriComponents builder = UriComponentsBuilder.fromHttpUrl(myMicroserviceClientConfiguration.getUrlDocsByName())
                .queryParam("pattern", name)
                .buildAndExpand(uriVars);
                
        ResponseEntity<List<Attachment>> response = restTemplate.exchange(builder.toUriString(),
                HttpMethod.GET,
                new HttpEntity<>(null),
                new ParameterizedTypeReference<List<Attachment>>() { }); // I need Stub this Call

        return  AttachmentList.builder().attachments(response.getBody()).build();
    }


    @Override
    public void processList(List<AttachmentDTO> request) {
        try {

            restTemplate.postForEntity(myMicroserviceClientConfiguration.getUrlSend(),
                    request,
                    byte[].class);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Other Classes

CustomResponse class

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@JsonInclude(JsonInclude.Include.NON_NULL)
public class CustomResponse {
    private String nameDocument;
    private String code;
    private int qtySent;
}

AttachmentDTO class

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class AttachmentDTO {
    @JsonProperty("typeDocument")
    private String typeDocument;
    @JsonProperty("name")
    private String name;
    @JsonProperty("base64Content")
    private String base64Content;
}

My Service Class

MyServiceImpl class

@Service
@RequiredArgsConstructor
public class MyServiceImpl implements MyService {
    private final MyMicroserviceClient myMicroserviceClient;
    @Override
    public CustomResponse fillList(String idContent, String number) {
        CustomResponse response = new CustomResponse();
        try {
            List<AttachmentDTO> listFiles = new ArrayList<>();
            AttachmentDTO attachmentDTO;
            
            AttachmentList pdfList = myMicroserviceClient.getDocsByName(idContent, "*.pdf");  // CALL ONE

            log.info("Size: " + pdfList.getattachments().size()); // HERE NullPointerException!!!

            for (Attachment attachment : pdfList.getAttachments()) {
                attachmentDTO = new AttachmentDTO();
                // Some Logic to add attachment to listFiles
            }

            myMicroserviceClient.processList(listFiles);  // CALL TWO

            response.setQtySent(listFiles.size());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return response;
    }
}

My Service Testing file file.

MyServiceSpec class

class MyServiceSpec extends Specification {

    private MyService myService
    private MyMicroserviceClient myMicroserviceClient

    void setup() {
        myMicroserviceClient = Mock(MyMicroserviceClient)
        myService = new MyServiceImpl(myMicroserviceClient)
    }

    def "FillList"() {
        given:
        def idContent = "0000"

        def attachment = Attachment.builder()
                .idContent("idContent")
                .name("name")
                .bytes("bytes".bytes)
                .build()

        def attachmentList = AttachmentList.builder()
                .attachments([attachment])
                .build()

        myMicroserviceClient.getDocsByName(idContent, "*.pdf") >> attachmentList // HERE my Stub!!!

        //Prevent Launch exception
        myMicroserviceClient.processList(_ as List<AttachmentDTO>) >> {}

        when: 
        CustomResponse response = myService.fillList(_ as String, number)

        // https://jakubdziworski.github.io/java/groovy/spock/2016/05/14/spock-cheatsheet.html
        // then: "Only one"
        // 1 *
        // then:  "At least one"
        // (1.._) * msCasosClienteNegClient.obtenerDocumentoBinario(_ as String)
        // then: "At most"
        // (_..1) * 
    }

}

In the MyMicroserviceClientImpl class I'm calling the method exchange of RestTemplate, as you can see, I have a ParameterizedTypeReference List.

In my MyServiceSpec Service Testing file I try to Stub the call getDocsByName (check the line with the comment // HERE my Stub!!!) of the Client, marked in my service CALL ONE.

When I run my test, I get NullPointerException in MyServiceImpl. I think happens that because I need to Stub restTemplate.exchange(...) too, but I don't know how to do it.

What Would be happening? and How to solve it?. Please some clue...


Solution

  • I think you mixed up two lines.

    Also number is undefined

    Try this:

       def "FillList"() {
            given:
            def idContent = "0000"
    
            def attachment = Attachment.builder()
                    .idContent("idContent")
                    .name("name")
                    .bytes("bytes".bytes)
                    .build()
    
            def attachmentList = AttachmentList.builder()
                    .attachments([attachment])
                    .build()
    
            def number = '42'
    
            when: 
            CustomResponse response = myService.fillList(idContent, number)
    
            then:
            1 * myMicroserviceClient.getDocsByName(idContent, "*.pdf") >> attachmentList
        }