我正在使用RestTemplate从控制器调用一个休息控制器,例如:
@RequestMapping(method = POST, consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@ResponseBody
public String formForUpload(@RequestParam("file") MultipartFile file) throws Exception {
final MultiValueMap<String, Object> parts=...;
restTemplate.postForObject("http://localhost:8080/rest/something",
parts, MultipartFile.class);
...
}
如何单元测试控制器调用的URL是否正确。有没有办法得到其余控制器的路径(例如使用这种反射技术)?
我不想进行集成测试!
答案 0 :(得分:2)
也许这不是正确答案,但也许有帮助。
假设其余控制器(假设MyRestController
)具有用@RequestMapping
注释的类声明,那么我假设您可以简单地获取当前定义的路径,如下所示:
final String controllerPath = MyRestController.class
.getAnnotation(RequestMapping.class).value()[0];
<强>更新强>
为什么不尝试对代码进行以下更改。它们基于Spring,JUnit和Mockito。假设您的控制器是类MyController
。
@Test
public void testUploadPostCallsToRestService() throws Exception {
final MockMultipartFile file = //create a mock for a file to be uploaded;
final MyController myController = new MyController();
final RestTemplate restTemplate = new RestTemplate();
final MockRestServiceServer mockServer = MockRestServiceServer.createServer(restTemplate);
ReflectionTestUtils.setField(myController, "restTemplate", restTemplate); //I assume you use Spring MVC from your tagging, isn't it?
final MockMvc mockMvc = MockMvcBuilders.standaloneSetup(myController).build();
mockServer.expect(requestTo("http://localhost:8080/rest/something"))
.andExpect(method(POST))
.andRespond(withStatus(OK)); //Or whatever your rest returns
mockMvc.perform(fileUpload("http://localhost:8080/path/to/my/controller")
.file(file)
.accept(MediaType.MULTIPART_FORM_DATA))
.andExpect(status().isOk()); //I hope you return this :)
mockServer.verify();
}
这对我很有用。基本上,我将模拟用于必须为RestTemplate
提供服务的其他服务服务器。因此,后者将调用与您指定的行为相同的模拟。然后,使用反射将其注入控制器。最后,我使用MockMvc上传文件并从控制器获得答案。
答案 1 :(得分:1)
方法参数值是否捕获了您正在寻找的内容?
您可以使用模拟框架来模拟其余模板并捕获方法调用参数。
控制器类(示例是工作代码,所以我想显示整个控制器类):
import org.springframework.beans.factory.annotation.*;
import org.springframework.http.MediaType;
import org.springframework.util.*;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;
public class MyController {
@Autowired
@Qualifier("MyRestTemplate")
private RestTemplate restTemplate;
@RequestMapping(method = RequestMethod.POST, consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@ResponseBody
public String formForUpload(@RequestParam("file") MultipartFile file) {
MultiValueMap<String, Object> parts = new LinkedMultiValueMap<>();
restTemplate.postForObject("http://localhost:8080/rest/something", parts, MultipartFile.class);
return "[{\"good-data\"}]";
}
}
单元测试:
import mockit.*;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;
import org.testng.Assert;
import org.testng.annotations.Test;
import java.util.ArrayList;
public class MyControllerTest {
@Test
public void testFormForUpload(@Mocked final RestTemplate restTemplate) {
MyController controller = new MyController();
Deencapsulation.setField(controller, restTemplate);
final ArrayList<String> urlValueHolder = new ArrayList<>();
new Expectations() {{
restTemplate.postForObject(withCapture(urlValueHolder), any, MultipartFile.class);
}};
controller.formForUpload(new MockMultipartFile("data-file.txt", "various data".getBytes()));
Assert.assertEquals(urlValueHolder.size(), 1);
Assert.assertEquals(urlValueHolder.get(0), "http://localhost:8080/rest/something");
}
}
注意:
RestTemplate
模拟作为测试方法的参数传递。这就是创建工作模拟所需要做的一切。withCapture
调用我作为RestTemplate#postForObject
的第一个参数。控制器使用的URL将存储在列表urlValueHolder
。我相信测试很简单,但我仍然建议重构控制器。我建议将url创建移动到单独的工厂类,而不是使用模拟和测试控制器来验证URL。对工厂进行简单的单元测试将是测试网址所需的全部内容。
答案 2 :(得分:0)
在Spring Hateoas项目中有一个用于生成控制器和控制器方法链接的类。具体来看看org.springframework.hateoas.mvc.ControllerLinkBuilder
。它将能够为简单的@RequestMapping
注释生成URL,但如果在同一个处理程序方法上使用多个映射,则无法确定要生成哪个。
此外,如果您的控制器处理程序方法返回String
,则链接构建器将抛出错误,因此将返回类型更改为Object
并且它将起作用。