Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Spring mockMvc integration #144

Open
1 task
Osmyslitelny opened this issue Jun 12, 2023 · 2 comments
Open
1 task

Spring mockMvc integration #144

Osmyslitelny opened this issue Jun 12, 2023 · 2 comments

Comments

@Osmyslitelny
Copy link

Osmyslitelny commented Jun 12, 2023

I'm submitting a ...

  • feature request

Do you need PR with spring mockMvc integration based on ResultHandler implementation?
I'm not sure this case is very popular, so, before creating PR I decided create this issues.

@tdeverdiere
Copy link

I was wondering how to implement swagger coverage on spring mvc. I first thought to use an Mvc filter :
mockMvc = standaloneSetup(new PersonController()).addFilters(new SwaggerCoverageFilter()).build();

Do you have a piece of code to show how it could work?

@tdeverdiere
Copy link

tdeverdiere commented Jan 16, 2024

I made an integration by implementing a ResultHandler for Swagger V3 and using it into a TestConfiguration.
The ResultHandler is largely inspired by https://github.com/viclovsky/swagger-coverage/blob/master/swagger-coverage-rest-assured/src/main/java/com/github/viclovsky/swagger/coverage/SwaggerCoverageV3RestAssured.java

The ResultHandler implementation :

import com.github.viclovsky.swagger.coverage.CoverageOutputWriter;
import com.github.viclovsky.swagger.coverage.FileSystemOutputWriter;
import io.swagger.v3.oas.models.*;
import io.swagger.v3.oas.models.media.*;
import io.swagger.v3.oas.models.parameters.*;
import io.swagger.v3.oas.models.responses.*;
import io.swagger.v3.oas.models.servers.Server;

import org.apache.commons.lang3.StringUtils;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.ResultHandler;
import org.springframework.web.servlet.HandlerMapping;

import java.net.URI;
import java.nio.file.Paths;
import java.util.Iterator;
import java.util.Map;

public class SwaggerCoverageResultHandler implements ResultHandler {

    private CoverageOutputWriter writer;

    public SwaggerCoverageResultHandler() {
        this.writer = new FileSystemOutputWriter(Paths.get("target", OUTPUT_DIRECTORY));
    }

    @Override
    public void handle(MvcResult result) throws Exception {
        var request = result.getRequest();
        var response = result.getResponse();

        Operation operation = new Operation();

        Map<String, String> pathAttributes = (Map<String, String>) request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
        pathAttributes.forEach((n, v) -> operation.addParametersItem(new PathParameter().name(n).example(v)));

        var queryString = request.getQueryString();
        request.getParameterMap().keySet().stream()
                .filter(name -> queryString.contains(name + "="))
                .forEach((n) -> operation.addParametersItem(new QueryParameter().name(n).example(request.getParameter(n))));

        for (Iterator<String> it = request.getHeaderNames().asIterator(); it.hasNext(); ) {
            String headerName = it.next();
            String headerValue = request.getHeader(headerName);
            operation.addParametersItem(new HeaderParameter().name(headerName)
                    .example(headerValue));
        }

        if ("POST".equalsIgnoreCase(request.getMethod()) && request.getContentLength() > 0) {
            MediaType mediaType = new MediaType();
            mediaType.setSchema(new Schema());

            request.getParameterMap().keySet().stream()
                    .filter(name -> !queryString.contains(name + "="))
                    .forEach((n) -> mediaType.getSchema().addProperties(n, new Schema().example(request.getParameter(n))));

            operation.requestBody(
                    new RequestBody().content(new Content().addMediaType(request.getContentType(), mediaType)));

        }

        var apiResponse = new ApiResponse();
        if (!StringUtils.isEmpty(response.getContentType())) {
            apiResponse.content((new Content()).addMediaType(response.getContentType(), new MediaType()));
        }
        operation.responses((new ApiResponses())
                .addApiResponse(String.valueOf(response.getStatus()), apiResponse));

        PathItem pathItem = new PathItem();
        pathItem.operation(PathItem.HttpMethod.valueOf(request.getMethod().toUpperCase()), operation);
        OpenAPI openAPI = new OpenAPI()
                .addServersItem(new Server().url(URI.create(request.getRequestURI()).getHost()))
                .path(request.getRequestURI(), pathItem);

        writer.write(openAPI);

    }
}

The configuration:

import org.springframework.boot.test.autoconfigure.web.servlet.MockMvcBuilderCustomizer;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.test.web.servlet.setup.ConfigurableMockMvcBuilder;

@TestConfiguration
public class SwaggerCoverageTestConfiguration {

    @Bean
    SwaggerCoverageMockMvcBuilderCustomizer swaggerCoverageMockMvcBuilderCustomizer() {
        return new SwaggerCoverageMockMvcBuilderCustomizer();
    }

    public static class SwaggerCoverageMockMvcBuilderCustomizer implements MockMvcBuilderCustomizer {

        @Override
        public void customize(ConfigurableMockMvcBuilder<?> builder) {
            builder.alwaysDo(new SwaggerCoverageResultHandler());
        }
    }
}

The configuration can then be imported into tests:
@ImportAutoConfiguration({SwaggerCoverageTestConfiguration.class})

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants