Макет против реализации. Как разделить оба подхода в одном тестовом классе? - PullRequest
0 голосов
/ 17 марта 2010

См. Следующий пробный тест с использованием Spring / Spring-MVC

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);
    }

}

Как видите, я делаю то, что предлагает Тройной паттерн A

  • Arrange (метод setUp)
  • Act (controller.handleRequest)
  • Assert (проверить и assertEquals)

Но я хотел бы протестировать и Mock, и класс реализации (OrderService), используя этот единственный класс Test . Поэтому, чтобы получить мою реализацию, я переписал свой класс следующим образом

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



}

Итак, как мне написать свой одиночный тест в Упорядочить и Mock, и внедрение OrderService без изменения метода моего теста (sucessSave и faultSave)

Я использую TestNG, но вы можете показать в JUnit, если хотите

С уважением,

Ответы [ 3 ]

2 голосов
/ 17 марта 2010

Это очень разные типы тестов. Первый типичный тестовый модуль для проверки контроллера. Второй - небольшой интеграционный тест, проверяющий взаимодействие контроллера и сервиса и конфигурацию пружины.

Так что не заменяйте первый тест вторым, он дополнительный!

1 голос
/ 18 марта 2010

Опять же, для меня это выглядит как два разных теста, но если вы будете непреклонны :) вот оно

@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 это должен быть тот же / аналогичный принцип. Опять же, я предполагаю, что вы провели исследование о том, почему вам нужен модульный тест и интеграционный тест в одном файле !!!

1 голос
/ 17 марта 2010

Для меня это были бы два разных теста (или, если быть точным, наборы тестов). Я бы сказал, что тестирование OrderController отличается от тестирования OrderService, даже если в обоих настройках теста есть похожие элементы. Модульное тестирование оценивает простые тесты, которые тестируют одну вещь (один вариант использования с одним объектом) за раз, и ИМХО по уважительной причине. Каждый класс имеет свой собственный интерфейсный контракт с его собственными граничными условиями, которые должны тестироваться отдельно.

Более того, просто протестировать OrderService через контроллер просто сложно, вместо того, чтобы вызывать его прямо из ваших методов тестирования. Скорее всего, при вызове через контроллер у вас не будет такой большой свободы в передаче «хитрых» параметров для выполнения граничных условий и т. Д.

Поэтому я рекомендую написать два отдельных тестовых класса, оба из которых полностью сосредоточены на тестировании своего собственного класса. Затем, как только вы будете удовлетворены своими модульными тестами и не будете иметь больше идей о том, что тестировать, вы можете взглянуть на методы настройки и вспомогательные методы, чтобы увидеть, можете ли вы удалить некоторое дублирование с помощью небольшого рефакторинга. Но для меня не главное - сохранить несколько строк кода в моих тестовых классах. Суть в том, чтобы протестировать то, что может сломаться, и сделать тесты простыми, чтобы понять, что именно тестирует на самом деле. Попытка тестирования двух объектов одновременно определенно затрудняет понимание ваших тестов (и, следовательно, их поддержку в долгосрочной перспективе).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...