2016-10-28 19 views
0

我的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來改變私人字段的值,但爲此我必須明確地實例化我的控制器,並因此在Autowired字段中存在一些問題。我試過這個:

@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字段的值?我應該重構我的代碼以不同的方式訪問它嗎?

SOLUTION 感謝鮑里斯·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")); 
    } 
} 

充分利用應用程序上下文我控制器豆起初不工作,因爲我在以前的代碼我是用我的測試類在WebMvcTest註釋中。

回答

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。

+0

謝謝Borys的回覆。我不確定要理解:在您的解決方案中,如何在同一個測試類中進行2個單元測試,一個用於測試development.mode = true,另一個用false?我的理解是,我將不得不創建兩個類,2個applicationContext文件,我錯了嗎? –

+0

嗯,是的,你需要創建兩個類。另一種選擇是使用ReflectionTestUtils,但從applicationContext中取出控制器,而不是直接實例化。 – borowis

+0

或者您可以爲該字段提供一個設置器 – borowis