在单元测试方法中更改应用程序属性值

时间:2016-10-28 09:00:15

标签: unit-testing spring-boot

我的REST API在POST请求中生成密码并将其存储在数据库中。出于开发目的,当application.properties文件中的development.mode标志设置为true时,我想将其放入响应中。

我想测试这个控制器,并检查如果标志为真,则密码在响应中,如果为false,则密码不是。

我想知道是否以及如何从每个测试方法动态设置此属性值。

这是我的控制者:

@RestController
public class PasswordController {

  @Value("${development.mode}")
  private boolean isDevelopmentMode;

  @RequestMapping(value = "/new", method = RequestMethod.POST)
  public ResponseEntity<String> generatePassword(@RequestParam(USERNAME_PARAM) String username) {
    String password = manager.generatePassword();

    String body = "";
    if (isDevelopmentMode) {
      body = "New password: " + password;
    }
    return new ResponseEntity<>(body, HttpStatus.OK);
  }    
}

我已经看过使用@PropertySource定义不同属性文件进行测试的文档,但它在类级别,我想避免创建一个不同的文件来改变标志。

我还看到帖子说你可以使用ReflectionUtils.setField来改变私有字段的值,但为此我必须明确地实例化我的控制器,因此在自动连接字段中存在一些问题。我试过这个:

@RunWith(SpringRunner.class)
@WebMvcTest(PasswordControllerTest.class)
public class PasswordControllerTest extends OtpTest {

  @Autowired
  private MockMvc mockMvc;

  @Test
  public void newRoute_developmentModeIsFalse_responseBodyIsEmpty() throws Exception {
    PasswordController controller = new PasswordController();
    ReflectionTestUtils.setField(controller, "isDevelopmentMode", false);
    MockMvc mvc = MockMvcBuilders.standaloneSetup(new PasswordController()).build();
    given(manager.generatePassword(any(String.class))).willReturn("123456");
    mvc.perform(post("/new").param(PasswordController.USERNAME_PARAM, "test_user")).andExpect(status().isOk()).andExpect(content().string(""));
  }
}

是否有可能在每个测试方法中设置@Value字段的值?我应该重构我的代码以不同方式访问它吗?

感谢Borys Zibrov,它使用了以下代码:

@RunWith(SpringRunner.class)
@WebMvcTest(PasswordController.class)
public class PasswordControllerTest extends OtpTest {

  @Autowired
  private MockMvc mockMvc;

  @Autowired
  private WebApplicationContext applicationContext;

  @Test
  public void newRoute_developmentModeIsTrue_passwordIsInTheResponseBody() throws Exception {
    PasswordController controller = applicationContext.getBean(PasswordController.class);
    ReflectionTestUtils.setField(controller, "isDevelopmentMode", true);

    given(manager.generatePassword(any(String.class))).willReturn("123456");

    mockMvc.perform(post("/new").param(PasswordController.USERNAME_PARAM, "test_user")).andExpect(status().isOk())
        .andExpect(content().string("New password: 123456"));
  }
}

从应用程序上下文中获取我的控制器bean起初并不起作用,因为在我以前的代码中我在WebMvcTest注释中使用了我的测试类。

1 个答案:

答案 0 :(得分:0)

您可以创建另一个applicationContext-tests.xml,通过以下方式将其连接到您的测试:

@RunWith(SpringRunner.class)
@WebMvcTest(PasswordControllerTest.class)
@ContextHierarchy({
    @ContextConfiguration(locations = "path_to applicationContext-tests.xml")
})
public class PasswordControllerTest extends OtpTest {

并覆盖该属性development.mode

您也可以坚持使用ReflectionTestUtils,而不是直接实例化,而是使用spring为您构造的applicationContext中的bean,然后在该bean上设置属性。

或者您可以为该字段提供一个setter。