2016-09-18 60 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

相关问题