Как настроить и очистить ресурс в Споке для набора тестов - PullRequest
0 голосов
/ 14 мая 2018

У меня есть этот код в моем наборе JUnit:

@RunWith(Suite.class)
@Suite.SuiteClasses({ MyJavaTest.class, MyAnotherJavaTest.class })
public class MyIntegrationSuite {
    @BeforeClass
    public static void beforeTests() throws Exception {
        Container.start();
    }

    @AfterClass
    public static void afterTests() throws Exception {
        Container.stop();
    }
}

Я хочу переписать его в Спок, но я не могу найти способ выполнить глобальную настройку, только setupSpec() и setup() этого недостаточно, так как у меня несколько спецификаций, и я хочу запустить Контейнер только один раз.

Я попытался оставить пакет как есть и передать ему спецификации Спока, но тесты спока пропускаются полностью (когда я добавлю extends Specifications).Вероятно, потому что Specification имеет @RunWith(Sputnik) и не играет с @RunWith(Suite), но я не уверен, как обойти это.

Есть ли способ выполнить глобальную настройку сSpock или выполнить спецификации Spock из пакета JUnit?

My pom.xml (есть заглушки, потому что я смешиваю код Java и Groovy):

<plugin>
  <groupId>org.codehaus.mojo</groupId>
  <artifactId>build-helper-maven-plugin</artifactId>
  <version>${buildhelper.plugin.version}</version>
  <executions>
    <execution>
      <id>add-groovy-test-source</id>
      <phase>test</phase>
      <goals>
        <goal>add-test-source</goal>
      </goals>
      <configuration>
        <sources>
          <source>${basedir}/src/test/groovy</source>
        </sources>
      </configuration>
    </execution>
  </executions>
</plugin>
<plugin>
  <groupId>org.codehaus.gmavenplus</groupId>
  <artifactId>gmavenplus-plugin</artifactId>
  <version>${gmavenplus.plugin.version}</version>
  <executions>
    <execution>
      <goals>
        <goal>generateTestStubs</goal>
        <goal>compileTests</goal>
        <goal>removeTestStubs</goal>
      </goals>
    </execution>
  </executions>
</plugin>

Ответы [ 3 ]

0 голосов
/ 19 мая 2018

Похвала за правильный ответ принадлежит Марку Брамнику , когда он написал:

В общем, Спок - это всего лишь JUnit (вот почему плагин безошибочного запуска может запускать его безлюбые дополнительные хлопоты), поэтому все подходы к наборам должны работать

. Хотя это правильный ответ, пример кода в его ответе относится к другому сценарию.Так что я собираюсь предоставить это здесь для справки.Я не ожидаю, что этот ответ будет принят, но если другие прочитают его, они также должны найти образец кода, объясняющий, как использовать эту функцию в Споке:

Образцы тестов Спока:

package de.scrum_master.stackoverflow

class FooTest extends Specification {
  def test() {
    expect:
    println "FooTest"
  }
}
package de.scrum_master.stackoverflow

class BarTest extends Specification {
  def test() {
    expect:
    println "BarTest"
  }
}

Набор тестов:

package de.scrum_master.stackoverflow

import org.junit.AfterClass
import org.junit.BeforeClass
import org.junit.runner.RunWith
import org.junit.runners.Suite
import spock.lang.Specification

@RunWith(Suite.class)
@Suite.SuiteClasses([FooTest, BarTest])
class SampleTestSuite {
  @BeforeClass
  static void beforeTests() throws Exception {
    println "Before suite"
  }

  @AfterClass
  static void afterTests() throws Exception {
    println "After suite"
  }
}

Журнал консоли:

Before suite
FooTest
BarTest
After suite
0 голосов
/ 24 января 2019

На самом деле, это возможно в споке, если ваш код может быть статическим.

Чтобы выполнить однократную инициализацию (раскрутить контейнер, запустить тестовый кластер zookeeper или что-то еще), просто создайте статический одноэлементный держательнапример:

class Postgres {

    private static PostgresContainer container

    static void init() {
        if (container != null)
            return

        container = new PostgresContainer()
        container.start()
    }

    static void destroy() {
        if (container == null)
            return

        container.stop()
        container = null
    }
}

Тогда вам нужен абстрактный класс для интеграционных тестов, например:

class IntegrationTest extends Specification {

    def setup() {
        init()
    }

    static void init () {
        Postgres.init()
    }

    def cleanup() {
        // do whatever you need
    }

    static void destroy() {
        Postgres.destroy()
    }
}

Теперь очистка немного сложная - особенно если у вас есть некоторыепотоки, не являющиеся демонами, не позволяющие завершить работу jvm.Это может привести к зависанию вашего набора тестов.Вы можете использовать shutdownHoook s или использовать механизм spock AbstractGlobalExtension.Вы можете выполнить некоторый код сразу после того, как спок выполнит все спецификации.Для нашего сценария postgres у нас будет что-то вроде:

class IntegrationTestCleanup extends AbstractGlobalExtension {

    @Override
    void stop() {
        IntegrationTest.destroy()
    }
}

Существует одна недостающая головоломка, чтобы она работала - вам нужно предоставить специальный файл в src/test/resources/META-INF.services/org.spockframework.runtime.extension.IGlobalExtension, который ссылается на ваше расширение.Этот файл должен содержать одну строку, указывающую на ваше расширение, например com.example.IntegrationTestCleanup

. Это заставит спока его распознать.Имейте в виду, что он будет выполняться в выделенном потоке спока.

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

0 голосов
/ 15 мая 2018

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

Кроме того, если у вас есть «тяжелый» общий ресурс, вы можете попробовать следующий подход:

abstract class SharedResourceSupport extends Specification {
   def static sharedSource = new SharedSource()
}


class SharedSource {
    public SharedSource() {
        println "Created shared source. Its our heavy resource!"
    }
}


class SpockTest1 extends SharedResourceSupport {
    def "sample test" () {
      expect:
        sharedSource != null
    }
}

class SpockTest2 extends SharedResourceSupport {
    def "another test" () {
      expect:
        sharedSource != null
    }
}

Обратите внимание, что общий ресурс определен как "статический", поэтому он будет создан только один раз, когда первый тест получит к нему доступ.

Как разные стратегии, чтобы справиться с этим: вы можете рассмотреть черты, если ваш тест уже наследуется от другого класса, или предоставить общий ресурс как Singleton, чтобы гарантировать, что существует только один экземпляр.

Попробуйте запустить оба теста, и вы увидите, что строка "Создан общий источник ..." вызывается только один раз

...