我怎样才能测试我的有假装客户的休息控制器?
How can I test a my rest controller that has feign clients?
我有一个使用 2 个 fein 客户端的休息控制器,我想用不同的样本编写和测试休息控制器,我不是编写 springboot 测试的专家。
在这种情况下,我没有要测试的存储库,只是假装通过休息控制器访问的客户端。下面是我的测试控制器代码
@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());
}
}
}
我见过的大多数测试都注入了一个存储库,但对于我来说
我没有那些,只是吸引客户,我做错了,
下面是我目前的测试
@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.
它就像编写任何其他 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())
}
}
您需要自己的 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 客户端调用它。
我有一个使用 2 个 fein 客户端的休息控制器,我想用不同的样本编写和测试休息控制器,我不是编写 springboot 测试的专家。
在这种情况下,我没有要测试的存储库,只是假装通过休息控制器访问的客户端。下面是我的测试控制器代码
@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());
}
}
}
我见过的大多数测试都注入了一个存储库,但对于我来说 我没有那些,只是吸引客户,我做错了,
下面是我目前的测试
@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.
它就像编写任何其他 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())
}
}
您需要自己的 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 客户端调用它。