Статьи

Больше Спок Лав — как я тестировал сложные сценарии установки

Я влюбился. Официально. Со споком.

Хорошо, мы только болтались немного, здесь и там. Но одна из вещей, которые я делаю, — это подготовка к обновленному докладу о дополнениях Spring Roo в SpringOne / 2GX. Вместо того, чтобы повторять то же самое снова, я хотел показать некоторую практическую помощь людям, пишущим дополнения, например, как писать хорошие тесты.

Кроме того, я хотел бы отметить несколько вещей, которые требуют дополнительной работы, поднять некоторые проблемы для очереди JIRA , чтобы мы могли улучшить Roo после SpringOne. Мы вернемся к этому позже в этой статье.

Тестирование доступности дополнений

Проверка доступности команды установки надстройки для доступа к оболочке Roo может быть немного сложной. Например, в дополнении Spock Roo я ожидаю, что оболочка пользователя выглядит так:

  • работает в контексте проекта
  • проект должен содержать две зависимости maven для спок-ядра и спок-пружины
  • проект должен содержать одну зависимость, чтобы плагин gmaven мог запускать тесты Спока

Итак, есть несколько сценариев для тестирования. Я начал тестировать их по отдельности. Плохой разработчик Во-первых, здесь есть своего рода таблица правды:

installedDependencies installedPlugins ожидаемый результат
никто никто правда
Депа, Депб никто правда
DEPA плагин правда
baddep никто правда
Депа, Депб плагин ложный
депабадверсия, депб плагин правда

Дано :

  • depa и depb = правильные две зависимости Maven,
  • baddep — это зависимость Maven, совершенно не связанная
  • depabadversion — та же зависимость, но другая версия
  • плагин это плагин gmaven от Codehaus
  • Ожидаемый результат — можем ли мы пойти дальше и установить надстройку (т.е. заменить то, что есть)

Когда я начал третий метод, я увидел столько дублирования, что начал отступать. Сначала я удалил все дополнительные вызовы, которые я делал, к различным методам (таким как projectOperations.getDependencies ()), что облегчало тестирование (и отладку). Затем я вытащил синтаксис таблицы данных.

Вот чем я закончил. Абсолютно босс, кстати :

package org.sillyweasel.roo.addons.spock
import org.springframework.roo.project.Dependency
import org.springframework.roo.project.Plugin
import org.springframework.roo.project.ProjectOperations
import org.springframework.roo.project.maven.Pom
import spock.lang.Unroll

class SpockOperationsImplTest extends spock.lang.Specification {

  static def depa = 
    new Dependency("org.springframework", "spock-core", "0.6-groovy-1.8")
  static def depb = 
    new Dependency ("org.springframework", "spock-spring", "0.6-groovy-1.8")
  static def depabadversion =
    new Dependency("org.springframework", "spock-core", "0.6-groovy-1.0")
  static def baddep = 
    new Dependency ("org.springframework", "sbad", "0.6-groovy-1.8")
  static def plugin = 
    new Plugin("org.codehaus.gmaven", "gmaven-plugin", "1.4")


  @Unroll
  def "install check - #situation"() {
    given:
      def pom = Mock(Pom.class)
      def operations = new SpockOperationsImpl()
      def projectOperations = Mock(ProjectOperations.class)
      operations.projectOperations = projectOperations

    when:
      def commandAvailable = operations.isSetupCommandAvailable()

    then:
      1 * projectOperations.isFocusedProjectAvailable() >> true
      1 * projectOperations.getFocusedModule() >> pom
      1 * pom.getDependencies() >> deps
      pom.getBuildPlugins() >> plugins
      assert commandAvailable == res

    where:
    deps          | plugins | res   | situation
    []            | []      | true  | "no installedDependencies or installedPlugin"
    [ depa, depb] | []      | true  | "all installedDependencies...
                                      but no installedPlugin"
    [ depa ]      | [plugin]| true  | "some installedDependencies...
                                       and installedPlugin"
    [ baddep ]    | []      | true  | "a different dependency and no plugins"
    [ depa, depb ]| [plugin]| false | "all installedDependencies and installedPlugin"
    [ depabadversion, depb ] 
                  | [plugin] | true | "bad version of a plugin"
  }
}

Что еще лучше …

Видите название метода вверху? Он имеет встроенную хэш-метку и использует поле `ситуация` плюс аннотация` @ Unroll`, чтобы превратить метод в пять отдельных методов тестирования на лету во время тестирования. Niiiice!

Проблемы Ру — тестирование аддонов

Почему я выполняю все свои тесты в Groovy, когда Roo является платформой на основе Java? Три причины:

  • Я хочу кататься на дополнениях,
  • Мне нужно понять слабые стороны API дополнения, чтобы попытаться улучшить его,
  • Мне нужно убедиться, что я тестирую большинство кода с наименьшими усилиями!

К средней точке: Roo основан на Maven и Spring. Он управляет файлом Maven `pom.xml`, а также Spring, Java и другими артефактами.

Поскольку файлы Maven управляются некоторыми классами-оболочками Java, написанными с целью генерации POM Maven , в настоящее время они достаточно хороши — вы можете заполнить их , например, с помощью Xml DOM , но они не являются тестируемыми по своей природе.

Например, класс Pom нельзя смоделировать, поэтому я не могу внедрить поддельный набор зависимостей или плагинов. То есть, если я не установлю две тестовые зависимости Maven, обе из которых Спок сказал мне использовать в качестве полезного совета! К ним относятся: `cglib-nodep` для имитации классов без интерфейса и` objenesis` для создания экземпляров классов как Mocks без конструкторов без аргументов. Для остроумия:

<dependency>
  <groupId>cglib</groupId>
  <artifactId>cglib-nodep</artifactId>
  <version>2.2.2</version>
  <scope>test</scope>
</dependency>

<dependency>
  <groupId>org.objenesis</groupId>
  <artifactId>objenesis</artifactId>
  <version>1.2</version>
  <scope>test</scope>
</dependency>

С этим я могу использовать:

def pom = Mock(Pom.class)

До встречи на SpringOne / 2GX

Я расскажу об этом и других методах в SpringOne / 2GX через две недели, а позже опубликую свою презентацию. Я надеюсь увидеть некоторых из вас там.