I'm writing a Scenario Outline in Specflow for Visual Studio. The objective is to test a Person Name comparer feature, in order to choose the best name between the two.
In my case, I have properties that belong to the names and properties external to them, which belong to the Person entity.
The comparison flow is mad in two parts: first I check the properties of the persons (owners of the names) to decide and if that doesn't yield me a result (meaning their properties are the same) then I check the names' properties.
I've written separate tests for the names' properties comparison, so in this test I only care about the Person properties and the relation between the names - which can be: Name1 < Name2, Name1 > Name2 or Name1 ≡ Name2.
By now I have written a scenario outline for each of those three cases, since I need to run each of the parameters in my Examples table once for each of those cases.
The code looks something like this:
Scenario Outline: Comparing names
Given I have a first name <name1>
And the first person has properties <properties1>
And I have a second name <name2>
And the second person has properties <properties2>
When I choose the best name
Then the best name should be <best name>
Examples:
| properties1 | properties2 |
| FirstName:"Carlos" | FirstName:"Johny" |
| LastName:"Smith" | FirstName:"Johny" |
| FirstName:"John",LastName:"Smith" | LastName:"Smith" |
Now in place of the names, I wrote this 3 times, one time for each case of the relation between the names, where I have the names hard-coded on the scenario.
Ideally, I would like to have a table of tables to be able to have a primary parameter that is ran with every line of the table.
Any idea how to implement that without having three different Scenario Outlines?
A SpecFlow table for creating each person might be the ideal solution. This allows you to pass values for each name, or a null value:
Scenario Outline: Comparing names
Given I have a first name <name1>
And the first person has properties:
| Field | Value |
| First Name | <first name 1> |
| Last Name | <last name 1> |
And I have a second name <name2>
And the second person has properties:
| Field | Value |
| First Name | <first name 2> |
| Last Name | <last name 2> |
When I choose the best name
Then the best name should be <best name>
Examples:
| name1 | first name 1 | last name 1 | first name 2 | last name 2| best name |
| X | Carlos | | Johnny | | X |
| X | | Smith | Johnny | | X |
| X | John | Smith | | Smith | X |
The advantage of this approach is you can expand the properties you set on each person.
Related
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 days ago.
Improve this question
The application I am working on has a hierarchy to the data tables it has, which is mostly straight forward. However, there is one field that is shared between most of the tables, that is acting like a secondary pk to the tables. Searching through google, this site and other places, I don't see any similar examples of this design. It appears that this design pattern is uncommon -- but does it's use create a problem that should be resolved?
Parent Table - Top level data object (ex: Product)
There are at least 10 sub tables (i.e., Manufacture, Materials, SalesRep, Vendor, etc...)
Each of the sub tables may or may not have other dependent tables.
The parent table, and some (but not all) of the dependent tables have a field called "Type" (saved as an integer). (ex: Physical, Electronic, Both)
The issue is, when selecting the data, the type_id is passed into all of the retrievals, for all of the tables. Doing so, allows for "Product" (ex, a "Book") to have one complete set of data (e.g., manufactures, materials, reps, vendors etc...) for one type of "Product" (ex: electronic book) and that same "Product" to have a completely different (or the same) set of data (e.g., manufactures, reps, etc...) for a different type of "Product" (ex: physical printed book).
Repeating the type_id through all of the tables duplicates the same data throughout the tables, resulting in essentially a two field pk for each record.
Currently:
--// Table: product
+------+-------------+----------------+
| id | date_issued | product_fields |
+------+-------------+----------------+
| 1 | 2010-08-20 | Book 1 |
| 2 | 2010-08-20 | Book 2 |
| 3 | 2010-08-20 | Book 3 |
+------+-------------+----------------+
--// Table: manufacturer
+------+------------+----------+-------------------+
| id | product_id | type_id | name |
+------+------------+----------+-------------------+
| 1 | 1 | 1 | Digital Printers |
+------+------------+----------+-------------------+
| 2 | 1 | 2 | Physical Printers |
+------+------------+----------+-------------------+
From what I can see, making "Type" relation a sub table under "Product", then having every other table be a dependent of product/type association is an alternative. However, to implement such a design change would require a great deal of refactoring both the database and code. While it is an alternative, is that the way others would do this?
Resulting in something like this:
--// Table: product
+------+-------------+----------------+
| id | date_issued | product_fields |
+------+-------------+----------------+
| 101 | 2010-08-20 | Book 1 |
| 102 | 2010-08-20 | Book 2 |
| 103 | 2010-08-20 | Book 3 |
+------+-------------+----------------+
--// Table: product_type_assoc
+------+-------------+-------------+
| id | product_id | type_id |
+------+-------------+-------------+
| 5 | 101 | 1 |
+------+-------------+-------------+
| 6 | 101 | 2 |
+------+-------------+-------------+
| 7 | 102 | 1 |
+------+-------------+-------------+
--// Table: manufacturer
+------+---------------------+-------------------+
| id | assoc_id | name |
+------+---------------------+-------------------+
| 1 | 5 | Digital Printers |
+------+---------------------+-------------------+
| 2 | 6 | Physical Printers |
+------+---------------------+-------------------+
An interim steps seems like having the current "type" in the product table, and passing that to the sub queries
Select from "Vendor" where "Product".id = 1 and "Type"_id = "Product".current_type
What do you think - Is this the preferred way, or is there a more commonly accepted design that does the same thing?
I have a Feature where the Scenarios in the Feature file is logically interconnected - hence my Scenarios cannot be run independently.
Nice: I created a CustomWorld to let Cucumber create and destroy the instance of my framework by itself.
Bad: Cucumber creates and destroys the instance for every scenario. But I want it to be created and destroyed for every feature instead of scenarios.
Here is my feature file
Feature: Table Headers
Scenario: Check the default headers ### My framework instance created here
Given I log in to the application ### A setup
When I navigate to the list page
Then the table should have the below headers
| Default Headers |
| First Name |
| Last Name |
| Age |
Scenario: Add columns ### want to reuse the instance created above and destroy automatically after this scenario
When I add the below columns to display
| Headers |
| City |
| Country |
Then the table should have the below headers
| Default Headers |
| First Name |
| Last Name |
| Age |
| City |
| Country |
And I log out from the application ### A teardown
A bite of my framework:
When I create an instance of my class, a selenium webdriver instance would be created, opens a browser and launches URL.
The real problem: I want to open the browser and launch URL only once per feature and not for every scenario.
This is breaking the rules of BDD and cucumber. You should not have dependencies across Scenario. What I would suggest is that your Given or Background do the setup and that steps are NOT explicit.
Given I am on the list page
|Application|
|###|
Then the table should have the below headers
| Default Headers |
| First Name |
| Last Name |
| Age |
Given I am on the list page
|Application|
|###|
When I add the below columns to display
| Headers |
| City |
| Country |
Then the table should have the below headers
| Default Headers |
| First Name |
| Last Name |
| Age |
| City |
| Country |
Also your final And is not a step and should not be included in your Scenario it should be part of AfterHook
I have a Google Sheet with one page for team leaders to list their desired team members (first names, last names, emails) by row--each TL fills in one row--, and a second page where team members are listed who have actually registered with my program.
Page 1
+------------------------+------------+---------------+------------+--------------------+
| Team Leader First Name | First Name | Email Address | First Name | Email Address |
+------------------------+------------+---------------+------------+--------------------+
| Danielle | Elizabeth | XXX#tamu.edu | Matthew | XXX#tamu.edu |
| Stoian | William | XXX#tamu.edu | Victoria | XXX#email.tamu.edu |
| Christa | Olivia | XXX#tamu.edu | | |
+------------------------+------------+---------------+------------+--------------------+
Page 2
+--------------------+-------------------------+
| Scholar First Name | Scholar Preferred Email |
+--------------------+-------------------------+
| elizabeth | xxx#gmail.com |
| william | xxx#tamu.edu |
+--------------------+-------------------------+
I want to be able to see at a glance which of the names listed by the TL on pg 1 have not registered and thus don't appear on pg 2.
In the example above, I want Olivia, Matthew, and Victoria's names to appear red because she does not show up on pg2 (which means they still need to register). Everyone else should appear normally.
I tried at first to importrange from pg1 to get a clean list of the team members, then conditional formatting to match against pg2, the idea I had being it shows up red if a name is not found.
Import range from page 2 to page 1 the scholar first name to F12:F14
Conditional Formatting: Apply to range B2:B999(first name list in page 1)
=NOT(OR(ISNUMBER(MATCH(TRIM(B2),$F$12:$F$13,0)),ISBLANK(B2)))
Conditional Formatting2: Apply to range D2:D999(Second First name list)
=NOT(OR(ISNUMBER(MATCH(TRIM(D2),$F$12:$F$13,0)),ISBLANK(D2)))
Note: Instead of importing, You could also reference the second sheet using INDIRECT.
I have many applications which I want to test, which have a largely overlapping set of features. Here is an oversimplified example of a scenario I might have:
Given <name> is playing a game,
When they shoot at a <color> target
Then they should <event>
Examples:
| name | color | event |
| Alice | red | hit |
| Alice | blue | miss |
| Bob | red | miss |
| Bob | blue | hit |
| Bob | green | hit |
It's a silly example, but suppose really I have a lot of players with different hit/miss conditions, and I want to run just the scenarios for a given name? Say, I only want to run the tests for Alice. There's still advantage to having all the hit/miss tests in a single Scenario Outline (since, after all, they're all closely related).
One approach would be to just duplicate the test for every name and tag them, so something like:
#Alice
Given Alice is playing a game
When she shoots at a <color> target
Then she should <event>
Examples:
| color | event |
| red | hit |
| blue | miss |
This way I can run behave --tags #Alice, But then I'm repeated the same scenario for every user, and that's a lot of duplication. Is there a good way to still compress all the examples into one scenario - but only selectively run some of them? What's the right approach here?
Version 1.2.5 introduced better ways to distinguish scenario outlines. It is now possible to uniquely distinguish them and thus select a unique scenario generated from an outline with --name= at the command line. For instance, suppose the following feature file:
Feature: test
Scenario Outline: test
Given <name> is playing a game,
When they shoot at a <color> target
Then they should <event>
Examples:
| name | color | event |
| Alice | red | hit |
| Alice | blue | miss |
| Bob | red | miss |
| Bob | blue | hit |
| Bob | green | hit |
Let's say I want to run only the test for Bob, red, miss. It is in the first table, 3rd row. So:
behave --name="#1.3"
will select this test. In version 1.2.5 and subsequent versions. A generated scenario gets a name which includes "#<table number>.<row number>" where <table number> is the number of the table (starting from 1) and <row number> is the number of the row.
This won't easily allow you to select all scenarios that pertain to a single user. However, you can achieve it in another way. You can split your examples in two:
Examples: Alice
| name | color | event |
| Alice | red | hit |
| Alice | blue | miss |
Examples: Bob
| name | color | event |
| Bob | red | miss |
| Bob | blue | hit |
| Bob | green | hit |
The table names will appear in the generated scenario names and you could ask behave to run all the tests associated with one table:
behave --name="Alice"
I do not know of a way to access the example name in steps and thus get rid of the first column.
The full set of details is in the release notes for 1.2.5.
I'm trying to set up the background for a cucumber Feature. Ideally I want to be able to do:
Given the following folders exist:
| id | parent_id | name |
| 1 | nil | folder1 |
| 2 | nil | folder2 |
| 3 | 2 | folder3 |
| 4 | 1 | folder4 |
| 5 | 1 | folder5 |
| 6 | 5 | folder6 |
However I can't do this as I can't set the ID of a particular model and so the first row may be created with an ID of 7 and therefore none of the other "child" rows can access it. Name is not unique so I can't do a find_by_name in the step definition. I've got a feeling it's gonna be some ugly nested array solution.
Any ideas how to achieve this?
I don't understand why you can't choose unique names for the purpose of your configuring the test?
The way I ended up doing it in my step definitions:
Given /^the following folders exist:$/ do |table|
table.hashes.each{|f|
folder = Folder.new(f)
folder.save
ActiveRecord::Base.connection.execute('UPDATE folders SET id = '+f['id'].to_s+' WHERE id = '+folder.id.to_s)
}
end