Reputation: 34081
I have a scenario that looks as the following:
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
}
As you can see, the Given
is repeating twice. The question is, would it be also correct, if I would just leave the second Given
as the following
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
}
Upvotes: 2
Views: 561
Reputation: 48420
Seconding @Lunivore answer, specify separate scenarios for supported and unsupported channel respectively:
scenario("Websocket client sends data to server over supported channel")
scenario("Websocket client sends data to server over unsupported channel")
Factoring out duplicated code in Given
clause could be achieved via fixtures like so
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
}
}
}
Note how Given("Websocket server on SAP is ACTIVE")
was moved to withFixture
. Also note the use of fixture.AsyncFeatureSpec
instead of AsyncFeatureSpec
to provide fixture support. This should output
[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
Personally, I would not bother with the fixture and keep the duplication for the sake of test source code readability, however I would definitely keep the scenarios separate.
Upvotes: 3
Reputation: 17637
In general it's usually a bad idea to have scenarios relying on other scenarios to set up their context. That's a pattern we call a "GivenScenario". It makes it harder to see the behaviour (you now have to read the whole of the first scenario to understand the context of the second) and if the first scenario fails, the second won't even be run.
It's also possible that someone who doesn't know that the second scenario is relying on the first might change the first or add one between them.
If you have some kind of behaviour that's "always on", most BDD tools put this in something they call the "Background". The equivalent of this in ScalaTest looks like the "BeforeAndAfter" trait (I'm not as familiar with ScalaTest so someone correct me if I'm wrong!).
So instead of having that "always on" active websocket in the scenario, you could move the behaviour to "Before".
Of course, the "background" in ScalaTest doesn't print when you run it; it's silent. But you could get around this by calling it anyway, and moving the English to either the title (note the addition of "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...
}
}
or the first given:
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...
}
}
(Again, not familiar with ScalaTest and it's been forever since I programmed Scala, so please correct any syntax errors; this answer is more focused on the principle. The documentation I found on this shows all steps as lower-case.)
The only time I tend to use GivenScenarios is when I'm being lazy (or pragmatic) and there's a (usually human) interaction which will result in one or more tries of something before getting a success:
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.
However, if it isn't readable like this, or the very first time the interaction in those first steps becomes anything other than trivial (e.g. you also have to fill in a captcha box), or the very first time I get an error in one of those steps, I'll refactor them out into separate scenarios.
If turning the support on and off in the client is an action that a human being could perform, then you could follow the same pattern, but the need for two "whens" in a row is a good sign that now there's more than one capability being illustrated here:
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
}
So probably not the right way to go for this one. If in doubt, avoid the GivenScenario pattern completely.
Upvotes: 4