Проблема параллелизма ScalaTest

Сценарий:

import org.scalatest.{ BeforeAndAfterAll, FeatureSpec, GivenWhenThen, Matchers }
import org.scalatest.concurrent.{ ScalaFutures, Futures }
import org.scalatest.time.{ Millis, Seconds, Span }

trait UniqueUserSpec extends FeatureSpec with GivenWhenThen with BeforeAndAfterAll with ScalaFutures {
  implicit override val patienceConfig =
    PatienceConfig(timeout = Span(5, Seconds), interval = Span(5, Millis))
  var user: Users = _
  override def beforeAll: Unit = {
    this.synchronized {
      user = TestHelper.createAndRegisterAUser()
    }
  }
}

В методе TestHelper.createAndRegisterAUser() все действия блокирующие и синхронные, от создания до записи БД и т.д.

В настоящее время:

class SomeActualTests extends UniqueUserSpec {
   feature("Something is possible") {
     scenario("some conditions") {
       Given("an api call is made to etc..")
       val req = url(API_END_POINT) / "route" <<? Map("test", "test")
       whenReady(req.POST) {
         response => {
           Then("The response status should be 200")
           response.getStatusCode shouldEqual 200
         }
       }
     }
   }
}

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

Если я создам отдельный user внутри каждого сценария, все будет работать. Если я попытаюсь использовать тот, который должен был создать beforeAll, объект не был записан в БД.

Что я делаю неправильно с параллелизмом, если что?

Есть ли лучший способ сделать что-то «до всех тестов» в Feature?


person flavian    schedule 27.12.2013    source источник
comment
Пока эксперт не вмешается, могу я предложить две вещи: (1) Попробуйте beforeAll на очень простом тестовом классе и постепенно увеличивайте сложность, пока не найдете точку, в которой beforeAll перестанет работать. (2) Если вы используете sbt, попробуйте запускать тесты последовательно, например. добавив это в build.sbt: parallelExecution in Test := false   -  person reggoodwin    schedule 27.12.2013


Ответы (1)


Вы пытаетесь создать пользователя перед каждым тестом, чтобы каждый тест получал своего пользователя? Если это так, вы хотите вместо этого BeforeAndAfterEach. BeforeAndAfterAll происходит один раз для всего пакета, прежде чем будут выполнены какие-либо тесты. Тогда все тесты могут использовать одного и того же пользователя.

Если BeforeAndAfterAll действительно то, что вы хотите, то мой следующий вопрос будет таков: действительно ли createAndRegisterAUser завершен к моменту возврата метода? Если нет, то, вероятно, в этом и заключаются ваши условия гонки.

Если это не так, то я бы спросил, синхронизировал ли ты доступ к пользователю var из своих тестов? Если нет, и эти тесты выполняются в разных потоках, модель памяти Java не гарантирует, что потоки чтения действительно увидят запись, выполненную beforeAll. Обычный способ, однако, запускать тесты в разных потоках — это использовать ParallelTestExecution, и я не вижу, чтобы вы использовали его здесь. Если бы вы использовали это, то он создал бы экземпляр тестового класса для каждого теста (ParallelTestExecution расширяет OneInstancePerTest), и это решило бы вашу проблему синхронизации. Так что скорее всего это тоже не то.

Если для решения этой проблемы требуется еще несколько шагов вперед и назад, может быть проще понять это на scalatest-users.

person Bill Venners    schedule 27.12.2013