簡體   English   中英

Spring Boot-REST控制器,使用MockMvc測試,環境屬性

[英]Spring Boot - REST controller, test with MockMvc, Environment properties

我在Spring Boot應用程序中有一個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生成的,這很方便,但並不總是清楚原因和目的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM