模拟与实施。如何在单个Test类中共享这两种方法?

时间:2010-03-17 20:50:31

标签: java unit-testing tdd mocking integration-testing

使用Spring / Spring-MVC

查看以下Mock Test
public class OrderTest {

    // SimpleFormController
    private OrderController controller;
    private OrderService service;

    private MockHttpServletRequest request;

    @BeforeMethod
    public void setUp() {

        request = new MockHttpServletRequest();
        request.setMethod("POST");

        Integer orderNumber = 421;
        Order order = new Order(orderNumber);

        // Set up a Mock service
        service = createMock(OrderService.class);
        service.save(order);

        replay(service);

        controller = new OrderController();
        controller.setService(service);
        controller.setValidator(new OrderValidator());

        request.addParameter("orderNumber", String.valueOf(orderNumber));
    }

    @Test
    public void successSave() {
        controller.handleRequest(request, new MockHttpServletResponse());

        // Our OrderService has been called by our controller
        verify(service);
    }

    @Test
    public void failureSave() {
        // Ops... our orderNumber is required
        request.removeAllParameters();

        ModelAndView mav = controller.handleRequest(request, new MockHttpServletResponse());

        BindingResult bindException = (BindingResult) mav.getModel().get(BindingResult.MODEL_KEY_PREFIX + "command");

        assertEquals("Our Validator has thrown one FieldError", bindException.getAllErrors(), 1);
    }

}

如您所见,我按照Triple A pattern

的建议行事
  • 安排(setUp方法)
  • 法案(controller.handleRequest)
  • 断言(验证和断言等)

但我想通过使用这个单一的Test类来测试Mock和Implementation类(OrderService)。因此,为了检索我的实现,我重新编写我的类,如下所示

@ContextConfiguration(locations="/app.xml")
public class OrderTest extends AbstractTestNGSpringContextTests {



}

那么我应该如何编写我的单个测试安排模拟和实现OrderService 而不更改我的测试方法(sucessSave和failureSave)

我正在使用TestNG,但如果你想要

,你可以在JUnit中显示

的问候,

3 个答案:

答案 0 :(得分:2)

这是非常不同的测试类型。第一个是测试控制器单元的典型单元测试。第二个是小型集成测试,测试控制器和服务的交互以及弹簧配置。

所以不要用第二个替换第一个测试,这是另外一个!

答案 1 :(得分:1)

对我来说,这将是两个不同的测试(或准确的测试集)。我会说测试OrderController与测试OrderService不同,即使两者的测试设置中都有类似的元素。单元测试值测试一次测试一个事物(一个用例有一个对象)的简单测试,有充分理由恕我直言。每个类都有自己的接口契约,有自己的边界条件,应该单独测试。

此外,尝试通过控制器测试OrderService只是很难,而不是直接在测试方法中调用它。当通过控制器进行呼叫时,您可能无法通过“棘手”参数来行使边界条件等。

因此,我建议编写两个单独的测试类,两者都完全专注于测试自己的类。然后,一旦您对单元测试感到满意并且没有更多的想法测试,您可以查看设置和帮助器方法,看看是否可以通过一些重构来删除一些重复。但对我而言,在我的测试类中保存几行代码不是主要问题。重点是测试可能破坏的东西,并保持测试简单,以明确这个测试实际测试的内容。试图同时测试两个对象肯定会使您的测试更难以理解(因此从长远来看也会维护)。

答案 2 :(得分:1)

对我来说,它看起来像两个不同的测试,但如果你要坚持:)这里是

@SpringJunit4Runner(....="app.xml")
public class OrderTest {

    @Resource
    private OrderController controller; //bean from app.xml

    @Resource
    private OrderService service; // actual order service
    private OrderService mockOrderService; //some mock order service
    private MockHttpServletRequest request;

    @BeforeMethod
    public void setUp() {
        request = new MockHttpServletRequest();
        request.addParameter("orderNumber", String.valueOf(orderNumber));
    }

    @Test
    public void successSave() {
        //test with orderService the way you would do it
    }

    @Test
    @DirtiesContext
    //need the annotation because we are changing our context beans i.e, ordercontroller
    //so for the next test the context would be recreated
    public void successSaveWithMock() {
        mockOrderService = //create mock service
        orderController.setOrderService(mockOrderService);
        //do the test with mock
    }
}

这适用于JUnit4,但对于您的TestNG,它应该是相同/相似的原则。我再次假设您已经完成了关于为什么需要在同一文件中进行单元测试和集成测试的研究!