我在Spring启动应用程序中有一个REST控制器,简化:
@RestController
@RequestMapping("/api")
public class MyRestController {
@Autowired
private Environment env;
private String property1;
@PostConstruct
private void init() {
this.property1 = env.getProperty("myproperties.property_1");
}
@GetMapping("/mydata")
public String getMyData() {
System.out.println("property1: " + this.property1);
...
}
在application.yml中我定义了类似于的属性:
myproperties:
property_1: value_1
当我使用REST控制器时,它按预期工作,读取值value_1,并在GET方法中存在。
现在我想用单元测试来测试它,类似的:
@RunWith(SpringRunner.class)
@SpringBootTest(classes = MyApp.class)
public class MyRestControllerTest {
@Autowired
private MappingJackson2HttpMessageConverter jacksonMessageConverter;
@Autowired
private PageableHandlerMethodArgumentResolver pageableArgumentResolver;
@Autowired
private ExceptionTranslator exceptionTranslator;
private MockMvc restMyRestControllerMockMvc;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
final MyRestController myRestController = new MyRestController();
this.restMyRestControllerMockMvc = MockMvcBuilders.standaloneSetup(myRestController)
.setCustomArgumentResolvers(pageableArgumentResolver).setControllerAdvice(exceptionTranslator)
.setConversionService(createFormattingConversionService()).setMessageConverters(jacksonMessageConverter)
.build();
}
@Test
public void getMyDataTest() throws Exception {
restMyRestControllerMockMvc.perform(get("/api/mydata"))
.andExpect(status().isOk());
}
执行测试中的方法时,属性property1的值为null。
这是为什么?
上面的代码部分由JHipster生成,我不确定这是否是最佳解决方案,只是重用它。
谢谢!
MockMvcBuilders.standaloneSetup不加载SpringContext,因此属性数据不可用。您可以直接在MyRestControllerTest中使用@Value(“$ {myproperties.property_1}”)注释来验证这一点 - 它将返回“value_1”值(但在MyRestController内部 - 将返回null)。
请将其更改为MockMvcBuilders.webAppContextSetup并注入WebApplicationContext。 (最后你可以通过它的构造函数将Environment bean注入MyRestController,但在我看来这是Spring hacking。)
警告:还记得(在Maven布局项目中)application.yml需要复制到src / test / resources。
代码示例:
@RestController
@RequestMapping("/api")
public class MyRestController {
@Autowired
private Environment env;
private String envProperty;
@Value("${myproperties.property_1}")
private String valueProperty;
@PostConstruct
private void init() {
this.envProperty = env.getProperty("myproperties.property_1");
}
@GetMapping("/mydata")
public String getMyData() {
System.out.println("envProperty: " + this.envProperty);
System.out.println("valueProperty: " + this.valueProperty);
return "";
}
@GetMapping("/myproblem")
public String getMyProblem() {
throw new IllegalArgumentException();
}
}
@RunWith(SpringRunner.class)
@SpringBootTest(classes = MyApp.class)
public class MyRestControllerTest {
private MockMvc restMyRestControllerMockMvc;
@Autowired
private WebApplicationContext context;
@Before
public void setup() {
final MyRestController myRestController = new MyRestController();
// this.restMyRestControllerMockMvc = MockMvcBuilders.standaloneSetup(myRestController)
// .build();
this.restMyRestControllerMockMvc = MockMvcBuilders.webAppContextSetup(context)
.build();
}
@Test
public void getMyDataTest() throws Exception {
restMyRestControllerMockMvc.perform(get("/api/mydata"));
}
@Test
public void getMyProblemTest() throws Exception {
restMyRestControllerMockMvc.perform(get("/api/myproblem"))
.andDo(MockMvcResultHandlers.print())
.andExpect(MockMvcResultMatchers.status().isConflict());
}
}
@ControllerAdvice
public class ControllerAdvicer {
@ResponseStatus(HttpStatus.CONFLICT)
@ExceptionHandler(IllegalArgumentException.class)
public String assertionException(final IllegalArgumentException e) {
return "xxx";
}
}
使用@Value
批注从app.yml中读取值
@RestController
@RequestMapping("/api")
public class MyRestController {
@Autowired
private Environment env;
@Value("${myproperties.property_1}")
private String property1;
@GetMapping("/mydata")
public String getMyData() {
System.out.println("property1: " + this.property1);
...
}
https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html
我将kasopey的答案标记为正确,因为它包含一个完整的答案,尽管其他响应者的答案也是正确的。
但我仍然想知道这些线是什么:
.setCustomArgumentResolvers(pageableArgumentResolver)
.setControllerAdvice(exceptionTranslator)
.setConversionService(createFormattingConversionService())
.setMessageConverters(jacksonMessageConverter)
因为用你的解决方案
MockMvcBuilders.webAppContextSetup(context)
那些方法不可用。如果有必要,如何实现同样的目标?
我的示例代码中缺少的方法如下所示:
... Create a FormattingConversionService which use ISO date format, instead of the localized one.
public static FormattingConversionService createFormattingConversionService() {
DefaultFormattingConversionService dfcs = new DefaultFormattingConversionService ();
DateTimeFormatterRegistrar registrar = new DateTimeFormatterRegistrar();
registrar.setUseIsoFormat(true);
registrar.registerFormatters(dfcs);
return dfcs;
}
而且,大部分代码都是由JHipster生成的,这非常方便,但并不总是清楚为什么以及为此是什么。