2016-09-18 109 views
0

回答想測試這樣的結構:的Mockito - 如何與自定義對象

@RequestMapping(value = "/test", method = POST) 
public ResponseEntity test(@RequestBody TestRequest request, Errors errors) { 

    testValidator.validate(request, errors); // Spring Validator interface impl 


    if (errors.hasErrors()) 
     return new ResponseEntity(HttpStatus.BAD_REQUEST); 

    return new ResponseEntity(HttpStatus.OK); 
} 

Errors對象由框架,而不是從我身邊經過,所以沒有更好的辦法來改變它的行爲測試但是使用了類似的Mockito的Answer的:

@RunWith(SpringRunner.class) 
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) 
public class ExampleTest { 

    @Autowired 
    private TestRestTemplate testRestTemplate; 

    @MockBean 
    private TestValidator testValidator; 

    @Test 
    public void test() { 

     doAnswer(new Answer<Errors>() { 

      @Override 
      public Errors answer(InvocationOnMock invocation) throws Throwable { 

      Errors errors = spy((Errors) invocation.getArguments()[1]); 
      //errors.rejectValue("id", "id", "id rejected"); 

      doReturn(true).when(errors).hasErrors(); 

      return errors; 
     } 

     }).when(testValidator).validate(any(), any()); 

     ResponseEntity re = testRestTemplate 
     .postForEntity("/test", new TestRequest(213L), String.class); 

     assertEquals(HttpStatus.BAD_REQUEST, re.getStatusCode()); 
    } 

...但問題是errors.hasErrors()儘管仍然在doAnswer試塊返回false和斷言失敗,因爲HTTP STA tus OK。我預計Errors對象將成爲調用.validate()後指定行爲的間諜,但似乎我做錯了什麼。

那麼,如何使用Mockito的doAnswer返回一個自定義對象?

+0

你這樣做,你如何「注入」你的testValidator到測試的實例? – 2016-09-18 10:58:14

+0

(我還建議你使用spring-mvc-test) – 2016-09-18 10:59:11

+0

@RC,使用新的Spring測試特性'@ MockBean'註釋,其行爲與Mockito的'@ Mock'完全一樣 – WildDev

回答

2

請勿在測試中使用postForEntity,因爲這會使其成爲框架本身的集成測試,以及您正在測試的實際類。

只是讓自己的Errors對象,這可能或可能不是一個模擬。如果這是一個模擬,那麼你可以按如下方式進行設置。

doReturn(true).when(mockErrors).hasErrors(); 

然後你的測試可以看起來像這樣。

@Test 
public void test() { 
    ResponseEntity re = objectThatYoureTesting.test(mockTestRequest, mockErrors); 
    assertEquals(HttpStatus.BAD_REQUEST, re.getStatusCode()); 
} 
1

doReturn(true).when(errors).hasErrors()僅在代碼塊使用spied errors實例時有效。如果你將返回的Error參考變量,模擬應該工作:

errors = testValidator.validate(request, errors); 

您將添加只是用於測試目的這項任務,但它也有利於代碼的可讀性;它強烈指示errors實例在validate方法內部被修改。

UPDATE:你可以用驗證返回的錯誤,比你可以窺視包裹驗證:

public class ValidatorWrapper { 
    public Errors validate(TestRequest request, Errors errors) { 
     testValidator.validate(request, errors); 
     return errors; 
    } 
} 

和測試代碼將類似於:

controller.setValidatorWrapper(spiedValidatorWrapper); 
doAnswer(new Answer<Errors>() { 

     @Override 
     public Errors answer(InvocationOnMock invocation) throws Throwable { 

     Errors errors = spy((Errors) invocation.getArguments()[1]); 
     //errors.rejectValue("id", "id", "id rejected"); 

     doReturn(true).when(errors).hasErrors(); 

     return errors; 
    } 

    }).when(spiedValidatorWrapper).validate(any(), any()); 
//rest of the test 

這應該做的伎倆。

+0

hm'testValidator'是Spring Validator接口實現,這就是爲什麼沒有選項使用返回值 – WildDev

+0

我假設有一個因爲你在回答塊中返回它。那麼就沒有辦法窺探'Error'實例。 – mtyurt

+0

@WildDev更新了答案,請檢查。 – mtyurt