Несколько данных в одном сценарии

У меня есть сценарий, который выглядит следующим образом:

scenario("Websocket client sends data to websocket server on SAP when is UP") {
  Given("Websocket server on SAP is ACTIVE")
  And("it supports websocket channel")
  When("Websocket client get started")
  Then("print message `Connection has been successfully established`")

  Given("Websocket server on SAP is ACTIVE")
  And("it does not support websocket channel")
  When("Websocket client get started")
  Then("throws RunException")
  succeed

} 

Как видите, Given повторяется дважды. Вопрос в том, было бы также правильно, если бы я просто оставил второй Given следующим образом

scenario("Websocket client sends data to websocket server on SAP when is UP") {
  Given("Websocket server on SAP is ACTIVE")
  And("it supports websocket channel")
  When("Websocket client get started")
  Then("print message `Connection has been successfully established`")

  And("it does not support websocket channel")
  When("Websocket client get started")
  Then("throws RunException")
  succeed

} 

person softshipper    schedule 21.04.2019    source источник
comment
Поскольку оба ваших сценария содержат один и тот же оператор Given, почему бы вам не перенести Websocket server on SAP is ACTIVE в качестве общего шага. Я бы посоветовал вам использовать отдельный сценарий, но оставить данное утверждение общим.   -  person Amit Prasad    schedule 22.04.2019
comment
Что вы имеете в виду под общим шагом. Не могли бы вы показать мне, что вы имеете в виду?   -  person softshipper    schedule 22.04.2019
comment
Это по тому же сценарию, но может случиться и другое.   -  person softshipper    schedule 22.04.2019


Ответы (2)


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

Также возможно, что кто-то, кто не знает, что второй сценарий опирается на первый, может изменить первый или добавить один между ними.

Если у вас есть какое-то поведение, которое «всегда включено», большинство инструментов BDD помещают это в то, что они называют «Фон». Эквивалент этого в ScalaTest выглядит как трейт «BeforeAndAfter» (я не так хорошо знаком со ScalaTest, поэтому кто-нибудь поправит меня, если я ошибаюсь!).

Таким образом, вместо того, чтобы иметь этот «всегда включенный» активный веб-сокет в сценарии, вы можете переместить поведение в «До».

Конечно, «фон» в ScalaTest не печатается, когда вы его запускаете; это тихо. Но вы можете обойти это, назвав его в любом случае и переместив английский язык в заголовок (обратите внимание на добавление «активного»):

class ExampleSpec extends FeatureSpect with BeforeAndAfter {

  before {
    server = startServer()
  }

  scenario("Websocket client sends data to active websocket server on SAP when is UP") {
    Given("it supports websocket channel")
    // etc...
  }
}

или первое данное:

class ExampleSpec extends FeatureSpect with BeforeAndAfter {

  before {
    server = startServer()
  }

  scenario("Websocket client sends data to websocket server on SAP when is UP") {

    Given("an active server with a client that supports websocket channel")
    // etc...
  }
}

(Опять же, я не знаком со ScalaTest, и с тех пор, как я программировал Scala, прошла целая вечность, поэтому, пожалуйста, исправьте любые синтаксические ошибки; этот ответ больше сосредоточен на принципе. ="nofollow noreferrer">Найденная мною документация показывает все шаги строчными буквами.)

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

Given Florence Forgetful is at the login page
When she puts in the wrong username
Then she should be told there was an error
When she puts in the wrong password
Then she should be told there was still an error
When she puts in the right username and right password
Then she should be taken to her home page.

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

Если включение и выключение поддержки в клиенте — это действие, которое может выполнить человек, то вы можете следовать той же схеме, но необходимость двух «когда» подряд — это хороший признак того, что теперь есть более одной возможности. проиллюстрировано здесь:

scenario("Websocket client sends data to websocket server on SAP when is UP") {
  Given("Websocket server on SAP is ACTIVE")
  And("websocket support is turned off")
  When("Websocket client get started")
  Then("throws RunException")
  When("websocket support is turned on")
  And("Websocket client get started") // <-- This is a second "When" here
  Then("print message `Connection has been successfully established`")
  succeed
} 

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

person Lunivore    schedule 22.04.2019

В дополнение к ответу @Lunivore укажите отдельные сценарии для поддерживаемого и неподдерживаемого канала соответственно:

scenario("Websocket client sends data to server over supported channel")
scenario("Websocket client sends data to server over unsupported channel")

Исключить дублированный код в предложении Given можно с помощью фиксаторов, например

class HelloSpec extends fixture.AsyncFeatureSpec with Matchers with GivenWhenThen {
  type FixtureParam = String // FIXME: Provide real SapWebSocket type

  override def withFixture(test: OneArgAsyncTest): FutureOutcome = {
    Given("Websocket server on SAP is ACTIVE")
    val activeSapWebsocketFixtureParam = "activateSapWebSocket()" // FIXME: implement activateSapWebSocket()
    withFixture(test.toNoArgAsyncTest(activeSapWebsocketFixtureParam))
  }

  feature("Kafka distribution to a server via websocket") {
    scenario("Websocket client sends data to server over supported channel") {
      givenActiveSapWebsocket =>
        And("given websocket channel is SUPPORTED")
        When("Websocket client get started")
        Then("print message `Connection has been successfully established`")
        succeed
    }

    scenario("Websocket client sends data to server over unsupported channel") {
      givenActiveSapWebsocket =>
        And("given websocket channel is UNSUPPORTED")
        When("Websocket client get started")
        Then("throws RunException")
        succeed
    }
  }
}

Обратите внимание, как Given("Websocket server on SAP is ACTIVE") был перемещен в withFixture. Также обратите внимание на использование fixture.AsyncFeatureSpec вместо AsyncFeatureSpec для предоставления поддержка приспособления. Это должно вывести

[info] Feature: Kafka distribution to a server via websocket
[info] - Scenario: Websocket client sends data to server over supported channel
[info]   + Given Websocket server on SAP is ACTIVE 
[info]   + And given websocket channel is SUPPORTED 
[info]   + When Websocket client get started 
[info]   + Then print message `Connection has been successfully established` 
[info] - Scenario: Websocket client sends data to server over unsupported channel
[info]   + Given Websocket server on SAP is ACTIVE 
[info]   + And given websocket channel is UNSUPPORTED 
[info]   + When Websocket client get started 
[info]   + Then throws RunException 

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

person Mario Galic    schedule 22.04.2019
comment
Спасибо Марио; совершенно дополнительный ответ от пользователя / эксперта ScalaTest POV! Именно такие вещи я надеялся, что кто-то опубликует. :) - person Lunivore; 22.04.2019