Параллельное выполнение тестов - PullRequest
26 голосов
/ 06 ноября 2011

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

Есть ли лучшие варианты, чем

  1. настройка всех тестов для запуска в последовательном режиме,
  2. использование отдельных имен файлов и списков для каждого теста?
class WriteAndReadSpec extends Specification{
  val file = new File("testFiles/tmp.txt")

  "WriteAndRead" should {
    "work once" in {
      new FileWriter(file, false).append("Foo").close
      Source.fromFile(file).getLines().toList(0) must_== "Foo"
    }
    "work twice" in {
      new FileWriter(file, false).append("Bar").close
      Source.fromFile(file).getLines().toList(0) must_== "Bar"
    }
  }

  trait TearDown extends After {
    def after = if(file.exists) file.delete
  }
}

Ответы [ 5 ]

36 голосов
/ 07 ноября 2011

В дополнение к тому, что написано о sbt выше, вы должны знать, что specs2 по умолчанию выполняет все примеры ваших спецификаций одновременно.

Вы все еще можете заявить, что для данной спецификации примеры должны выполняться последовательно. Для этого просто добавьте sequential в начало вашей спецификации:

class WriteAndReadSpec extends Specification{
  val file = new File("testFiles/tmp.txt")

  sequential

  "WriteAndRead" should {
   ...
  }
}
4 голосов
/ 05 декабря 2011

Фиксированная последовательность тестов для наборов может привести к взаимозависимости тестовых случаев и бремени обслуживания.

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

// Create temp file.
File temp = File.createTempFile("pattern", ".suffix");
// Delete temp file when program exits.
temp.deleteOnExit();
2 голосов
/ 06 ноября 2011

Вики-ссылка Пабло Фернандес дал свой ответ довольно хорошо, хотя в примере есть небольшая ошибка, которая может скинуть одну (хотя, будучи вики я могу и исправила) Вот project/Build.scala, который на самом деле компилирует и производит ожидаемые фильтры, хотя на самом деле я не пробовал его с тестами.

import sbt._
import Keys._

object B extends Build
{
  lazy val root =
    Project("root", file("."))
      .configs( Serial )
      .settings( inConfig(Serial)(Defaults.testTasks) : _*)
      .settings(
         libraryDependencies ++= specs,
         testOptions in Test := Seq(Tests.Filter(parFilter)),
         testOptions in Serial := Seq(Tests.Filter(serialFilter))
       )
      .settings( parallelExecution in Serial := false : _*)

  def parFilter(name: String): Boolean = !(name startsWith "WriteAndReadSpec")
  def serialFilter(name: String): Boolean = (name startsWith "WriteAndReadSpec")

  lazy val Serial = config("serial") extend(Test)

  lazy val specs = Seq(
        "org.specs2" %% "specs2" % "1.6.1",
        "org.specs2" %% "specs2-scalaz-core" % "6.0.1" % "test"
      )
}
2 голосов
/ 06 ноября 2011

Кажется, существует третий вариант, который группирует последовательные тесты в конфигурации и запускает их отдельно, а остальные параллельно.

Проверьте этой вики , найдите "Приложение для параллельного выполнения" .

0 голосов
/ 02 января 2015

В других ответах объясняется, как их использовать, чтобы они выполнялись последовательно.

Хотя они и являются действительными ответами, на мой взгляд, лучше изменить свои тесты, чтобы они могли работать параллельно. (если возможно)

В вашем примере - используйте разные файлы для каждого теста. Если у вас есть БД - используйте разных (или случайных) пользователей (или любую возможную изоляцию) и т.д ...

...