Cucumber - Is it possible to share a table between Scenarios? - ruby

Does anyone know its its possible to define a table once in a .feature file & then access it from multiple scenarios? I'm not chaining scenarios but many of them do need to pass tables with the same data to their step definitions - also for this reason examples won't really do what I need here.
Thanks!

One possible solution is to tag all your scenarious where you need a table:
#given_have_table
Scenario: test
Then I am happy
Then bind Before hook to this tag and call step that declares your table from within Before hook definition:
Before("#given_have_table") do
steps Q%{
Given I have the following table:
| a | b |
| 1 | 2 |
}
end
Alternative approach is to construct required table in tagged Before hook without calling step:
Before("#given_have_table") do
#tbl = { :a => 1, :b => 2 }
end

Related

Clean architecture: use case mixing

I'm trying to understand how clean architecture works, last project i had a user, he can add a payment card and buy a subscription (example use case), but when it's new user, add and buy integrated as one step
Use case sample
According to what has been read, it should have two "Interactors", one "AddPayment" and "Purchase", , but... how can I mix:
The user can do both separately, but when he is new, in registration process he adds the payment method and makes the charge in one step,
I think I should have an "Add and pay" use case, but it would have repeated code and a broken paradigm, I see these options:
Make a third use case with repeated code
Merge from controller
Make a use case that calls the other two
How have you solved it?
I usually make a base use case that calls the other two. For this base use case I define a new request model that contains the request models of the others . The same applies for the response model. But sometime the request or response models have something in common and I create more condensed models.
I think that a base use case fits best to the include relationship of the use case uml model.
+-----------+
| AddAndPay |
+-----------+
| |
V V
+-----+ +-----+
| Add | | Pay |
+-----+ +-----+
The AddAndPay use case also handles failures of one of the use cases. E.g. if pay fails you might not want to add a payment card. Maybe you must invoke a RemovePaymentCard use case then or your transaction boundary is the AddAndPay use case.

Cucumber Transforms for Multiple Variable Scenario Outline Examples

I have a set of functionally similar websites that I want to write cucumber specs for to drive both development, and selennium browser tests. The site are in different languages and will have different URLs, but will have mainly the same features.
An example scenario might be
Scenario Outline: Photo Gallery Next Action
Given I visit a "<photo-gallery-page>"
When I click "<next-button>" in the gallery
Then the photo should advance
Examples:
| photo-gallery-page | next-button |
| www.site1.com/photo-gallery | Next |
| www.site2.com/la-galerie-de-photos | Suivant |
This is fine when I have a small number of scenarios and examples. However I'm anticipating hundred of scenarios and fairly regular launch of new sites. I want to avoid having to edit each scenario to add examples when launching new sites.
I think I need to store all my example variables in a per site configuration, so that I can run the same scenario against all sites. Then I can add new configurations fairly easily and avoid editing all the scenario examples and making them unreadable.
site[:en].photo-gallery-page = 'www.site1.com/photo-gallery'
site[:fr].photo-gallery-page = 'www.site2.com/la-galerie-de-photos'
site[:en].next-button = 'Next'
site[:fr].next-button = 'Suivant'
One option would be to store this config somewhere, then generate the site specific gherkin files using a script. I could then run these generated gherkins which would contain the required examples
I'm wondering if there's an easier way. My other idea was if I can use table transforms to replace the example blocks. I've had a read, but as far as I can tell I can only transform a table (and replace it with a custom code block) if it's an inline table within a step. I can't transform an examples block in the same way.
Have I understood that correctly? Any other suggestions on how best to achieve this?
I wonder if there's a better way... This all feels very brittle.
What if:
Given I follow a link to the gallery "MyGallery"
And the gallery "MyGallery" contains the following photos:
|PhotoID|PhotoName|
|1 |MyPhoto1 |
|2 |MyPhoto2 |
And the photo "MyPhoto1" is displayed
When I view the next photo
Then the next photo "MyPhoto2" should be displayed
Note that you've taken out the notion of button names, etc. - implementation details that are presumably better defined in your step definitions. The behaviour you're defining is simply going to a gallery, viewing an image, requesting the next one, viewing the next image. Define how in your step definitions.
There's some reading I found very useful on this topic at http://cuke4ninja.com/. Download the PDF and check out the web automation section (it details the web automation pyramid).
To address your configuration problem, maybe you could define some kind of config. class and supply it to the step definition files via dependency injection. You could make it site specific by loading from different config. files as you suggested in its constructor. Step definitions could pull the relevant site specific data from the config. class' properties. I think this would make your scenario is more readable and less brittle.

What is the best strategy for BDD testing which relies on data

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?
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.

NHibernate 3.1 Linq with Contains and Any

We are in the process of upgrading to NH3.1 which is going well -
everything is working as far as we can tell with existing code. One of
the motivations to move to NH3 from 2 has been to leverage the Linq
support and generally it is working really well. However I am
struggling with some more complex where clauses, specifically when I
want to check based on a sub-collection:
var results = from r in registrations
where (
from p in persons
where p.ExplicitManagers.Any(m => m.Manager == manager)
select p
).Contains(r.Registrant)
select r;
where the model is:
p is a Person and a registration r has a registrant of type Person
p contains a collection of ExplicitManager associative entities which
hold a reference to another Person (manager).
note: registrations is an IQueryable<Registration>.Query() and persons
in an IQueryable<Person>.Query().
Essentially I am trying to restrict the registrations to where person1
is an explicit manager of p. I can do this via joins but not through
the Contains subquery.
I get the following error:
"System.InvalidOperationException :
Sequence contains more than one
matching element"
the reason for doing this as a sub-query is because ultimately I need
to externalize the logic for checking the managers to make it reusable
(it actually is more complex but I have simplified it for this example
because it is the Any within a Contains which is causing the grief).
Contains seems to work fine when not having a sub-query with Any.
Is this something I am doing wrong, or is it something unsupported or
a bug, and is there another way of achieving the same thing?
Many thanks for any help you can give.
Whilst Contains doesn't seem to work properly, using Any does:
var results = from r in registrations
where (
from p in persons
where p.ExplicitManagers.Any(m => m.Manager == manager)
select p
).Any(p=>p == r.Registrant)
select r;
Can you execute the sub query on its own without problems?
var result = from p in persons
where p.ExplicitManagers.Any(m => m.Manager == manager)
select p;

Query a many to many relationship with Entity Framework and .NET 3.5

My problem is actually two-fold. First, I'm pretty new to EF but I've used it with some success by taking shortcuts earlier. Though, for this particular project I plan to take the time to learn.
What I have at this point is a very simplistic database structure:
Post
===================
Id Title
-------------------
1 Hello world
2 Foo bar baz
Tag
===================
Id Title
-------------------
6 test
7 todo
PostTags
===================
PostId TagId
-------------------
1 6
1 7
2 7
Using EF, it generates a model with two entities: Post and Tag.
What I'm trying to accomplish:
I'm attempting to query the model for all posts given an array of tagIds (6 and 7 for instance). However I can't figure out what I need to do to make that work.
Previously I've cheated in the way that I added an auto-incremental PK to the mapping table (BlogPosts) and added it into the EF-model but it was more of an ugly hack in order to move forward. I'd rather learn how to do it right this time.
This will work in EFv4. Try it in EFv1:
var tagIds = new int[] { 6, 7 };
var query = context.Tags
.Where(t => tagIds.Contains(t.Id))
.SelectMany(t => t.Posts);
Edit:
I checked it and collection valued parameters + Contains were added in EFv4 so above example doesn't work in EFv1. This thread in MSDN forum provides workaround to allow IN operator in EFv1. Another recommended workaround is simply upgrade to EFv4 because there are many other improvements including significant improvement of performance.

Resources