spring 我如何测试一个有伪客户端的my rest控制器?

pprl5pva  于 2023-06-04  发布在  Spring
关注(0)|答案(3)|浏览(395)

我有一个使用2个fein客户端的rest控制器,我想用不同的示例编写和测试Rest控制器,我不是编写springboot测试的Maven。
在这个场景中,我没有要测试的存储库,只是假装通过REST控制器访问客户端。下面是我的测试控制器代码

@RestController
public class CustomerController {

    @Autowired
    private CustomerClient customerClient;

    @Autowired
    private PaymentsClient paymentsClient;

    @RequestMapping(path = "/getAllCustomers", method = RequestMethod.GET)
    public ResponseEntity<Object> getAllCustomers() {
        List<Customer> customers = customerClient.getAllCustomers();
        return new ResponseEntity<>(customers, HttpStatus.OK);

    }

    @RequestMapping(path = "/{customerId}", method = RequestMethod.GET)
    public ResponseEntity<Object> get(@PathVariable() long customerId) {
        try {
            Customer c = customerClient.getCustomerById(customerId);
            if (c != null) {
                return new ResponseEntity<>(c, HttpStatus.OK);
            } else {
                return ResponseEntity.status(HttpStatus.NOT_FOUND).body("Customer Not Found");
            }
        } catch (Exception e) {
            e.printStackTrace();
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(e.getMessage());
        }
    }

    @RequestMapping(path = "/{customerId}", method = RequestMethod.PATCH)
    public ResponseEntity<Object> UpdateCustomer(@PathVariable() Long customerId, @RequestBody Customer customer) {
        Customer c;
        try {
            c = customerClient.update(customerId, customer);
            if (c != null) {
                return new ResponseEntity<>(c, HttpStatus.OK);
            } else {
                return ResponseEntity.status(HttpStatus.NOT_FOUND).body("Customer Not Found");
            }
        } catch (Exception e) {
            e.printStackTrace();
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(e.getMessage());
        }
    }

    @RequestMapping(path = "", method = RequestMethod.POST)
    public ResponseEntity<Object> saveCustomer(@RequestBody Customer customer) {
        Customer c;
        try {
            c = customerClient.saveCustomer(customer);
            return new ResponseEntity<>(c, HttpStatus.OK);
        } catch (Exception e) {
            e.printStackTrace();
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(e.getMessage());
        }
    }

    @RequestMapping(path = "/registerPayment", method = RequestMethod.POST)
    public ResponseEntity<Object> saveCustomer(@RequestBody Payment payment) {
        Payment p = null;
        Customer c = null;
        try {
            c = customerClient.getCustomerById(payment.getCustomerId());
            p = paymentsClient.saveCustomer(payment);
            return new ResponseEntity<>(p, HttpStatus.OK);
        } catch (Exception e) {
            if (null == c) {
                return ResponseEntity.status(HttpStatus.UNPROCESSABLE_ENTITY).body("Customer Does not Exist");
            } else {
                e.printStackTrace();
                return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(e.getMessage());
            }
        }
    }

我见过的大多数测试都注入了一个存储库,但对于我的情况,我没有这些,只是fein客户端,我做错了,
下面是我目前的测试

@RunWith(SpringRunner.class)
@SpringBootTest
@ActiveProfiles("test")
public class CustomerControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @InjectMocks
    private CustomerController customerController;

    @Before
    public void setup() {

        mockMvc = MockMvcBuilders.standaloneSetup(customerController).build();
    }

    @Test
    public void getAllCustomers() {

        try {
            this.mockMvc.perform(get("/getAllCustomers")).andExpect(status().isOk())
                    .andExpect(content().json("[{\n" + "    \"customerId\": 24,\n"
                            + "    \"firstName\": \"Benjamin\",\n" + "    \"secondName\": \" Masiga\",\n"
                            + "    \"email\": \"ben@ben.com\"\n" + "  }"));
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

}

我得到下面的错误,

NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.test.web.servlet.MockMvc' available: expected at least 1 bean which qualifies as autowire candidate.
pkln4tw6

pkln4tw61#

它就像编写任何其他JUnit测试一样简单。

@RunWith(SpringRunner.class)
@SpringBootTest
@ActiveProfiles("test")
public class CustomerControllerTest {

    @Mock
    private CustomerClient customerClient;

    @InjectMocks
    private CustomerController customerController;

    @Test
    public void getAllCustomers() {
        List<Customer> customers = new ArrayList<>();
        customers.add(new Customers("name"));
        Mockito.when(customerClient.getAllCustomers()).thenReturn(customers);
        Mockito.assertEquals(customers.toString(),customerController.getAllCustomers())
    }

}
rryofs0p

rryofs0p2#

@InjectMocks应该只在你想运行忽略Spring框架的纯Java单元测试时使用。当您运行@SpringBootTest时,Spring框架会尝试初始化并将所有bean注入到应用程序上下文中。@InjectMocks不会这样做!如果你想测试你的SpringBoot应用程序是否配置正确,你应该将你的FeignClients添加为@MockBeans。SpringFramework将用mock版本替换类的真实示例。然后,您可以像修改任何其他模拟对象一样修改行为。下面是一个例子:
集成测试

@RunWith(SpringRunner.class)
@SpringBootTest
@ActiveProfiles("test")
public class CustomerControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @Autowired
    private CustomerController customerController;

    @MockBean
    private CustomerClient customerClient;

    @MockBean
    private PaymentsClient paymentsClient;

    @Before
    public void setup() {

        mockMvc = MockMvcBuilders.standaloneSetup(customerController).build();
    }

    @Test
    public void getAllCustomers() {
Customer customer = new Customer();
customer.setCustomerId(24);
customer.setFirstName("Benjamin");
customer.setSecondName("Masiga");
customer.setEmail("ben@ben.com");
 Mockito.when(customerClient.getAllCustomers()).thenReturn(Arrays.asList(customer));
   
            this.mockMvc.perform(get("/getAllCustomers")).andExpect(status().isOk())
                    .andExpect(content().json("[{\n" + "    \"customerId\": 24,\n"
                            + "    \"firstName\": \"Benjamin\",\n" + "    \"secondName\": \" Masiga\",\n"
                            + "    \"email\": \"ben@ben.com\"\n" + "  }"));
   
    }

}
kxe2p93d

kxe2p93d3#

您需要自己的feign.Client,它可以在MockMvc之外工作:

import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.function.Function.identity;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.request;

import feign.Client;
import feign.Request;
import feign.Response;
import java.io.UncheckedIOException;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.ResultActions;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;

public class MockMvcFeignClient implements Client {

    private final MockMvc mockMvc;

    public MockMvcFeignClient(MockMvc mockMvc) {
        this.mockMvc = mockMvc;
    }

    @Override
    public Response execute(Request request, Request.Options options) {
        URI requestUrl = URI.create(request.url());
        List<String> uriVars = new ArrayList<>();
        String urlTemplate = fillVarsAndGetUrlTemplate(requestUrl, uriVars);
        HttpMethod method = HttpMethod.valueOf(request.method());
        byte[] body = request.body();
        HttpHeaders httpHeaders = convertHeaders(request);

        MockHttpServletRequestBuilder requestBuilder = request(method, urlTemplate, uriVars.toArray())
                .headers(httpHeaders)
                .content(body);

        MockHttpServletResponse resp;
        try {
            ResultActions resultActions = mockMvc.perform(requestBuilder);
            resp = resultActions.andReturn()
                    .getResponse();
        } catch (Exception e) {
            throw new IllegalStateException("Error while executing request", e);
        }

        return convertResponse(request, resp);
    }

    static String fillVarsAndGetUrlTemplate(URI requestUrl, List<String> uriVars) {
        StringBuilder urlTemplate = new StringBuilder(requestUrl.getPath());
        if (requestUrl.getQuery() != null) {
            urlTemplate.append('?');
            String[] pairs = requestUrl.getRawQuery().split("&");
            for (int i = 0; i < pairs.length; i++) {
                String pair = pairs[i];
                int separator = pair.indexOf('=');
                String paramName;
                String paramValue;
                if (separator < 0) {
                    paramName = pair;
                    paramValue = null;
                } else {
                    paramName = pair.substring(0, separator);
                    try {
                        paramValue = URLDecoder.decode(pair.substring(separator + 1), UTF_8.name());
                    } catch (UnsupportedEncodingException e) {
                        throw new UncheckedIOException(e);
                    }
                }
                urlTemplate.append(i == 0 ? paramName : "&" + paramName);
                if (paramValue != null) {
                    urlTemplate.append("={").append(paramName).append('}');
                    uriVars.add(paramValue);
                }
            }
        }
        return urlTemplate.toString();
    }

    private static HttpHeaders convertHeaders(Request request) {
        HttpHeaders headers = new HttpHeaders();
        request.headers().forEach((header, values) -> headers.put(header, new ArrayList<>(values)));
        return headers;
    }

    private static Response convertResponse(Request request, MockHttpServletResponse resp) {
        return Response.builder()
                .request(request)
                .status(resp.getStatus())
                .body(resp.getContentAsByteArray())
                .headers(resp.getHeaderNames().stream()
                        .collect(Collectors.toMap(identity(), resp::getHeaders)))
                .build();
    }
}

并使用它创建您的虚拟客户端:

return Feign.builder()
        .client(new MockMvcFeignClient(mockMvc))
        ...

因此,对于可以进行MockMvc集成测试的测试,现在可以通过feign客户端调用它。

相关问题