Spring Boot - REST控制器,使用MockMvc进行测试,环境属性

问题描述 投票:0回答:3

我在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生成,我不确定这是否是最佳解决方案,只是重用它。

谢谢!

java spring-boot mockmvc
3个回答
1
投票

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";
    }

}

1
投票

使用@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


0
投票

我将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生成的,这非常方便,但并不总是清楚为什么以及为此是什么。

© www.soinside.com 2019 - 2024. All rights reserved.