What are some strategies for writing BDD tests, which can test behaviour that relies on certain data being in the system?
For example, say I was working with the following scenario:
Feature: Search for friend
In order to find a friend
As a user
I want to search my list of friends
And filter by 'first name'
How could this test ever succeed unless/until some "dummy" friends had been entered into the system?
More to the point, what "dummy" criteria would the test utilize?
Should I hard-code the name of a friend, assuming it to already exist in the database?
But what if I move my code to a new environment with a fresh database?
Or, should I write code to manually insert dummy data into the system prior to executing each test?
But this would be modifying the internal state of the application from within a test framework, which seems like a bad approach, since we're supposed to be treating the program as a black-box, and only dealing with it through an interface.
Or, would I create other scenarios/tests, in which the data is created using an interface of the program? 开发者_如何学Go
For example, 'Feature: Add a new friend to my list'. Then I could run that test, to add a user called 'Lucy', then run the 'Search for friend' tests to search for 'Lucy', which would now exist in the database.
But, then I'd be introducing dependencies between my scenarios, which contradicts the common advice that tests should be independently runnable.
Which one the best strategy? Or is there a better way?
You would use the Given clause in your scenario to get the system into the appropriate state for the test. The actual implementation of this would be hidden in the step definition.
If the data is going to shared across your scenarios then you could have in a background step:
Background:
Given I have the following friends:
| andy smith |
| andy jones |
| andrew brown |
To add these friends you could either insert records directly into the database:
def add_friend(name)
Friend.create!(:name => name)
end
or automate the UI, e.g.:
def add_friend(name)
visit '/friends/new'
fill_in 'Name', :with => name
click_button 'Add'
end
For the scenarios themselves, you would need to think of key examples to validate the behaviour, e.g.:
Scenario: Searching for a existing person by first name
When I search for 'andy'
Then I should see the friends:
| andy smith |
| andy jones |
But I should not see "andrew brown"
Scenario: Searching for a non-existing person by first name
When I search for 'peter'
Then I should not see any friends
You're correct that tests should be independent, so you shouldn't rely on other scenarios to leave the database in a particular state. You will probably need some mechanism to clean-up after each test. For example, the 'database-cleaner' gem if you're using Cucumber and Rails.
You are referring to BDD and Integration style of testing. If you use a decent ORM (NHibernate?) you can create an in-memory database before each test runs and clean it up after the test succeeds and since the db is in memory, it won't take much time comparing to running it on a real database.
You can use the pre/post test hooks to fit in the data necessary for your scenario and clean it up afterwards so that your tests can be run without depending on each other.
精彩评论