Подтвердить что ты не робот

Интеграция и модульные тесты в крупном проекте Grails

Обычно сложнее писать модульные тесты из-за необходимости иметь дело с макетными объектами, чем тесты интеграции в большом проекте Grails. Эта статья даже предполагает, что мы даже можем вообще отказаться от единичных тестов и написать только те тесты интеграции, к которым я склонен соглашаться.

Единственным недостатком, который я вижу, является скорость выполнения теста интеграции по сравнению с тем же unit test.

Каковы ваши мысли об этом из вашего фактического опыта работы над крупным проектом Grails?

Если мы пишем unit test, который тестирует точно такой же метод, а также записывает интеграционный тест, который также проверяет точно такой же метод, является ли это обычным способом написания тестов?

Что вы получили с точки зрения соотношения модульных тестов и тестов интеграции в самом крупном проекте Grails?

Вы успешно завершили крупный проект Grails без написания каких-либо тестов?

4b9b3361

Ответ 1

Я всегда пишу свои тесты как единичные тесты, если это возможно. Я делаю это, потому что:

  • модульные тесты выполняются быстрее
  • Я предпочитаю тестировать каждый компонент изолированно, а не тестировать все компоненты, объединенные вместе, поскольку это облегчает идентификацию источника ошибки.
  • среда тестирования модулей проще (например, контекст приложения Spring), поэтому существует меньше потенциальных источников сбоев, которые не связаны с выполняемым тестом.

Примером того, где я должен был бы написать тест интеграции, является то, что я хочу протестировать Spring bean, который я определил в resources.groovy. Хотя я мог бы создать экземпляр класса и протестировать его напрямую, мой тест затем должен был знать текущий класс реализации этого bean (который может измениться).

В долгосрочной перспективе я считаю, что на самом деле сложнее писать интеграционные тесты, потому что стоимость их поддержки с течением времени выше, чем модульные тесты. Groovy/Grails отлично поддерживает насмешливость /stubbing, поэтому стоимость издевательских зависимостей в модульных тестах относительно невелика. Вот пример реального мира из одного из моих модульных тестов, где I:

  • mock messageSource Spring bean, который обычно доступен только в тесте интеграции
  • mock два класса команд, чтобы я мог вызвать метод validate(), проверить свойство .errors и т.д.

class MyUnitTests extends GrailsUnitTestCase {

    MessageSource messageSource

    protected void setUp() {

        super.setUp()
        // mockForConstraintsTests is a method provided by GrailsUnitTestCase
        [Complex, CategoryCommand].each {mockForConstraintsTests(it)}

        // 'mockMessage' will be returned by every method call on messageSource
        messageSource = {Object[] args -> "mockMessage"} as MessageSource
    }
}

Ответ 2

Я работал над тремя крупными приложениями grails и бесчисленными меньшими. Мой текущий проект включает в себя комплексные и интеграционные тесты (в настоящее время 2110 модульных тестов и 493 интеграционных теста).

Я потратил кучу времени, пытаясь улучшить скорость тестирования, а также сделать тесты более удобными.

Мои интеграционные тесты часто являются гибридом, где, если я тестирую службу, я мог бы издеваться над некоторыми другими услугами/методами, вызываемыми для обеспечения того, чтобы я получал нужные мне значения, но оставляю в других интеграционных элементах для реализации HQL или интеграция базы данных. Для этого я использую экземпляры прототипов, которые обычно являются одноэлементными службами, чтобы я мог обманывать экземпляр службы без загрязнения последующих тестов.

Я нахожу плагин build-test-data бесценным для создания поддерживаемых модульных тестов, поскольку он позволяет мне создавать тестовые данные, где я явно заполняю нужные мне элементы и пусть плагин заполнит другие требуемые детали. Создание тестовых данных в тестах интеграции для меня проще, чем издевательство над модульными тестами.

Если вы используете как интеграционные, так и модульные тесты, в конечном итоге скорость запуска всех тестов последовательно станет препятствием. Моя команда использует splitTests.groovy script для выделения двух отдельных потоков, один для модульных тестов, один для интеграционных тестов. Это увеличивает наши тесты на 40% быстрее. Дальнейшее распараллеливание возможно, но мы еще не пошли туда (и текущие сценарии граффити grails довольно неприятны под обложками, я с нетерпением жду перезаписи gradle в grails 2.0).

Модульные тесты хороши для удара по всем условным уголкам и трещинам метода (хотя, если у вас слишком много, ваша циклическая сложность, вероятно, слишком высока, и вы должны реорганизовать). Интеграционные тесты полезны для осуществления интеграции с базами данных и услуг, а также помогают понять, что вы нарушили, когда вы меняете часть кода.

Я думаю, что мужество рефакторинга, которое вы получаете от высокого уровня тестирования, частично зависит от некоторых тестов, которые являются интеграционными тестами. Если все, что у вас есть, это модульные тесты, которые не взаимодействуют с другими фрагментами кода, вы не будете предупреждены об затронутых областях при изменении кода и потому что groovy является динамическим языком, компилятор, вероятно, не поможет вы также найдете эти области.

Ответ 3

В этой статье мы даже можем даже отказаться от единичных тестов и написать только те тесты интеграции, к которым я склонен

Эта статья написана с помощью Grails 1.0

Отметьте дополнительную статью. Тот же столбец, тот же автор