问题
I have a feature "Importing articles from external website". In my first scenario I test importing a list of links from the external website.
Feature: Importing articles from external website
Scenario: Searching articles on example.com and return the links
Given there is an Importer
And its URL is "http://example.com"
When we search for "demo"
Then the Importer should return 25 links
And one of the links should be "http://example.com/demo.html"
In my steps I have the 25 links in a @result
array.
In my second scenario I want to take one of the links and test the fact that I parse the article correctly.
Now obviously I do not want to go to the external website every time, especially now that the first scenario passes.
How do I proceed here so I can keep testing without making the HTTP requests for the first scenario? Or should I run it once and persist the @result
array across the rest of the scenarios so I can keep working with the actual result set?
回答1:
This is intentionally very difficult to do! Sharing state between tests is generally a Very Bad Thing, not least because it forces your tests to run in sequence (your first scenario MUST run before the subsequent ones, not something Cucumber supports explicitly).
My suggestion would be to re-think your testing strategy. Hitting external services in tests is a great way to make them run slowly and be unreliable (what happens when the external service goes down?). In this case I'd suggest using something like webmock or vcr to create a fake version of the external site, that returns the same response as you'd expect from the real site, but you can hit as many times as you like without the worry of performance or unavailability.
回答2:
I found that it is technically possible to use
@@global_variable in step definition to share the global state.
However, just like other people points, it may not be a good idea.
I tried to avoid repeated login steps in the similar scenarios. Again, it may not be a good practice. Use the trick when really necessary
回答3:
You shouldn't share state between scenarios. A scenario describes a piece of the intended behavior for the whole system, and it should be possible to run just one scenario. E.g. if you have run the entire test suite, and you find that a single scenario fails, you should be able to run just that one scenario in order to investigate what went wrong.
Your problem arises because you try to contact external systems. That is not advisable. Not only does it make you test suite run more slowly, but it also makes the test dependent on the external system, to which you have no control. If the external system is not running, your tests are not running. If the external tests does not contain the data you expect, your tests will fail, even though there are no bugs in your own system. And you end up letting your tests be controlled by what you expect to be in the external systems, instead of controlling what is in the external system based on what you need to test.
Instead you should mock out the external system, and let your scenarios control what the mocked system will deliver:
Scenario: Query external system
# These two lines setup expected data in a mocked version of the external system
Given there the system x contains an article named "y"
And the article contains the text "Lorep ipsum"
When I query for article "y"
Then I should see the text "Lorem ipsum"
This scenario is independent of any actual data in external systems, as it explicitly specifies what needs to be there. And more importantly, it clearly describes how your own system should behave.
The scenario in that form can also be communicated to stakeholders, and they can validate the scenarios without any prior knowledge to any test data present in those external systems.
It may take some time getting a proper framework running, but in the end, it will be worth it.
回答4:
I use a file. I have a case to create a new user, then I want to logout and log back in with that same user in other features.
I generate the user with:
@randomName = [*('a'..'z')].sample(8).join
Then I save the user to a file:
File.open("randomName.txt", 'w') {|f| f.write("#{@randomName}") }
Later, when I need that data in other feature, I use:
@randomName = data = File.read("randomName.txt")
回答5:
Making scenario dependent or sharing the data between scenarios is not a good practice.
some solutions 1) Cucumber provide Background tag to run preconditions for each scenario.
2) Cucumber provides hooks @Before and @after which can be customized for each scenario.
来源:https://stackoverflow.com/questions/11164255/how-to-share-state-between-scenarios-using-cucumber