Péter Veres
Péter Veres

Reputation: 1163

How to Unit test Spring-Boot REST endpoints with MockMVC where the path mappings are environment variables?

I'm trying to write Unit tests for a service that relies heavily on environment variables for its configuration. Unit tests work fine for the service layer but I'm running into problems trying to set up MockMVC tests for the endpoints that read their addresses directly from environment variables.

I tried to set the variable directly in the test but I assume that it would require the application context to populate the controller side value and I'm trying to avoid that for simple unit tests.

Using: Java11, Mockito2, JUnit5, SpringBoot2.2.0.M6

Controller:

@RestController
public class OutgoingMessageAPI {

    private MessagingService service;

    public OutgoingMessageAPI(MessagingService service) {
        this.service = service;
    }

    @PostMapping("${MQTT_CLIENT_API_OUTGOING_MESSAGE}")
    public ResponseEntity postMessage(@RequestBody @Valid Message message) {
         service.handleOutgoingMessage(message);
    }

}

Test where I manually generate the MockMVC BeforeEach test:

@ExtendWith(MockitoExtension.class)
@DisplayName("Outgoing Message API Test")
class OutgoingMessageAPITest {

    private MockMvc mockMvc;

    @Mock
    private ObjectMapper objectMapper;

    @Mock
    private MessagingService messagingService;

    @InjectMocks
    private OutgoingMessageAPI outgoingMessageAPI;

    private Message validIncomingMessage;
    private String validIncomingMessageJSON;

    @BeforeEach
    void beforeEach() throws JsonProcessingException {
        mockMvc = MockMvcBuilders.standaloneSetup(outgoingMessageAPI).build();

        validIncomingMessage = new Message());
        validIncomingMessageJSON = new ObjectMapper().writeValueAsString(validIncomingMessage);
    }

    @Test
    @DisplayName("A valid message is posted")
    void postMessageValid() throws Exception {
        var endpoint = "/endpoint";
        System.setProperty("MQTT_CLIENT_API_OUTGOING_MESSAGE", endpoint);
        mockMvc.perform(post(endpoint)
                    .content(validIncomingMessageJSON)
                    .contentType("application/json"))
                .andExpect(status().isAccepted());
    }

The received error is:

    Invalid mapping on handler class [com.tlvlp.iot.server.mqtt.client.rpc.OutgoingMessageAPI]: public org.springframework.http.ResponseEntity com.tlvlp.iot.server.mqtt.client.rpc.OutgoingMessageAPI.postMessage(com.tlvlp.iot.server.mqtt.client.persistence.Message)
    Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'MQTT_CLIENT_API_OUTGOING_MESSAGE' in value "${MQTT_CLIENT_API_OUTGOING_MESSAGE}"

Upvotes: 0

Views: 945

Answers (1)

i.bondarenko
i.bondarenko

Reputation: 3572

In a standalone setup there is no support for placeholder values embedded in request mappings. So you should use StandaloneMockMvcBuilder.addPlaceholderValue(...):

@BeforeEach
void beforeEach() throws JsonProcessingException {
    mockMvc = MockMvcBuilders.standaloneSetup(outgoingMessageAPI)
            .addPlaceholderValue("MQTT_CLIENT_API_OUTGOING_MESSAGE", "/endpoint")
            .build();
    ...
}

Upvotes: 2

Related Questions