一种情况下的多个给定

Multiple Given in one scenario

我有一个如下所示的场景:

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

} 

一般来说,让场景依赖于其他场景来设置它们的上下文通常不是一个好主意。我们称之为 "GivenScenario" 的模式。这使得行为更难看到(您现在必须阅读整个第一个场景才能理解第二个场景的上下文)并且如果第一个场景失败,第二个场景甚至不会 运行.

也有可能不知道第二种情况依赖第一种情况的人可能会更改第一种情况或在它们之间添加一个。

如果您有某种 "always on" 的行为,大多数 BDD 工具会将其放在他们称为 "Background" 的东西中。 ScalaTest 中的等效项看起来像 "BeforeAndAfter" 特征(我对 ScalaTest 不太熟悉,所以如果我错了,请有人纠正我!)。

因此,您可以将行为移至 "Before"。

,而不是在场景中使用 "always on" 活动的 websocket

当然,当您 运行 时,ScalaTest 中的 "background" 不会打印;它是沉默的。但是你可以通过调用它来解决这个问题,并将英文移动到标题(注意添加 "active"):

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以来一直如此,所以请纠正任何语法错误;这个答案更侧重于原理。The documentation I found on this将所有步骤显示为lower-case.)

我唯一倾向于使用 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.

但是,如果它不是这样可读的,或者 第一次,那么第一步中的交互将变得不重要(例如,您还必须填写一个验证码框),或者 第一次 我在其中一个步骤中遇到错误,我会将它们重构到不同的场景中。

如果在客户端打开和关闭支持是人类可以执行的操作,那么您可以遵循相同的模式,但连续需要两个 "whens" 是一个好兆头现在这里说明了不止一种功能:

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 模式。

第二个@Lunivore 回答,分别为支持和不支持的频道指定不同的场景:

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

可以通过 fixtures 像这样

来实现 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 

就个人而言,为了测试源代码的可读性,我不会费心固定装置并保留重复项,但是我肯定会将场景分开。