5. Goals Make money by selling our stuff online
Display catalog
Features/Epics
Order products
Build a wishlist
User stories
Browse Catalog
In order to find stuff I would like to buy
As a customer
I want to be able to browse through the
catalog
6. User stories
Browse Catalog
In order to find stuff I would like to buy
As a customer
I want to be able to browse through the
catalog
Acceptance criteria
☑
See
all
the
top-‐level
categories
in
the
catalog
☑
Browse
through
the
sub-‐categories
☑
See
all
the
products
in
a
category
7. User stories
Browse Catalog
In order to find stuff I would like to buy
As a customer
I want to be able to browse through the
catalog
Acceptance criteria
☑
See
all
the
top-‐level
categories
in
the
catalog
☑
Browse
through
the
sub-‐categories
☑
See
all
the
products
in
a
category
Scenario: See all top-level categories
Given I want to browse the catalog
When I am on the home page
Then I should see the following product categories: Clothing, Accessories, Shoes
Automated acceptance test
22. 22
1 Discover your acceptance criteria
2 Automate your acceptance criteria
3 Implement your acceptance criteria
4 Execute your acceptance tests
23. 23
1 Discover your acceptance criteria
Feature: Browse Catalog
In order to find items that I would like to buy
As a customer
I want to be able to browse through the catalog
Story: Browse by category
In order to find items more easily
As a customer
I want to be able to browse through the product categories
Acceptance Criteria
See all the top-level categories
Browse through the category hierarchy
Should display the correct products for each category
Each category should have the correct sub-categories
Define acceptance criteria for each story
24. 24
1 Discover your acceptance criteria
Acceptance Criteria
See all the top-level categories
Browse through the category hierarchy
Should display the correct products for each category
Each category should have the correct sub-categories
Scenario: See all top-level categories
Given I want to browse the catalog
When I am on the home page
Then I should see the following product categories: Clothing, Accessories, Shoes
Clarify the acceptance criteria with examples
25. 25
2 Automate your acceptance criteria
Story: Browse by category
In order to find items more easily
Acceptance Criteria
As a customer top-level categories
See all the
I want Browse through the category the product categories
to be able to browse through hierarchy
Scenario: See all top-level categories
Should display the correct products for each category
Given I want to browse the catalog
Each category should have the correct sub-categories
When I am on the home page
Then I should see the following product categories: Clothing, Accessories, Shoes
Narrative:
In order to find items more easily
As a customer
I want to be able to see what product categories exist
Scenario: See all top-level categories
Given I want to browse the catalog
When I am on the home page
Then I should see the following product categories: Clothing, Accessories, Shoes
We now have an executable requirement
26. 26
2 Automate your acceptance criteria
...but they will be reported as ‘pending’
27. 27
3 Implement your acceptance criteria
Narrative:
In order to find items more easily
As a customer
I want to be able to see what product categories exist
Scenario: See all top-level categories
Given I want to browse the catalog
When I am on the home page
Then I should see the following product categories: Clothing, Accessories, Shoes
46. Stay on top of your scenarios
Better visibility on what is done
More targeted reporting
47. Keep your scenarios organized
Goal:
In order to increase revenue from commissions on classified ads sales
As the head of the classified ads department
I want to increase the number of items sold via our classified ads
Capability
In order to increase the number of items I sell Feature
As a seller In order to increase sales of advertised articles
I want buyers to be able to view ads for items As a seller
they might want to purchase I want potential buyers to be able to display only the ads for
articles that they might be interested in purchasing.
Story
In order to find the items I am interested in faster
As a buyer
I want to be able to list all the ads with a particular keyword in
the description or title.
49. Customize Thucydides to work for you
RequirementsTagProvider
getRequirements()
getParentRequirementOf(testOutcome)
Capability
In order to increase the number of items I sell
As a seller
I want buyers to be able to view ads for items they might want to
Feature
In order to increase sales of advertised articles
As a seller MyRequirementProvider
I want potential buyers to be able to display only the ads for articles
MYPROJ-123
Story
In order to find the items I am interested in faster
As a buyer
I want to be able to list all the ads with a particular keyword in the
description or title.
Meta:
@issue MYPROJ-123
Scenario: Search by keyword
Given that I want to find products in the "<range>" range
When I search for products by keyword "<keywords>"
Then I should see a product with the title <expectedTitle>
50. Use tags for orthogonal concerns
• Non-functional requirements
• Iterations
• Current iteration vs regression tests
• Acceptance tests vs more detailed tests
• Related features
• System components
• ...
51. Use tags for orthogonal concerns
@RunWith(ThucydidesRunner) Tagging in JUnit
@Issue("NC-1")
@WithTag(name="Browse Ads")
class BrowseAdsByCategory {
@Managed
public WebDriver webdriver
@ManagedPages(defaultUrl = "http://www.newsclassifieds-uat.appspot.com")
public Pages pages
@Steps
BuyerSteps buyer
@Test
void "Browse ads by category"() {
buyer.opens_home_page()
buyer.chooses_classification "Furniture & Homewares"
buyer.should_see_search_results_for "Furniture & Homewares"
buyer.chooses_entry(1).from().other_results()
buyer.should_see_details_for_the_selected_ad()
buyer.returns_to_search_results()
buyer.should_see_search_results_for "Furniture & Homewares"
}
}
52. Use tags for orthogonal concerns
Meta:
@tag component:search
Tagging in JBehave
Scenario: Search by keyword
Given that I want to find products in the "<range>" range
When I search for products by keyword "<keywords>"
Then I should see a product with the title <expectedTitle>
Examples:
| range | keywords | expectedTitle |
| Simone | Simone | 3by3 Simone |
| Grey Steel Classic | Steel | 3by3 Grey Steel Classic |
| KV Bags | KV | KV Classic Satchel |
53. Use tags for orthogonal concerns
Meta:
@tag component:search
Scenario: Search by keyword
Given that I want to find products in the "<range>" range
When I search for products by keyword "<keywords>"
Then I should see a product with the title <expectedTitle>
Examples:
| range | keywords | expectedTitle |
| Simone | Simone | 3by3 Simone |
| Grey Steel Classic | Steel | 3by3 Grey Steel Classic |
| KV Bags | KV | KV Classic Satchel |
58. Page Objects To The Rescue!
Better encapsulation
Easier to read
Easier to maintain
Still a bit unclear what we are doing
59. Test Steps To The Rescue!
Step methods focus on what we are doing
60. Test Steps To The Rescue!
Step implementations detail the how
61. Test Steps To The Rescue!
Steps are ordinary methods
@Step
public void proceedToPayment() {
adPreviewPage.proceedToPayment();
}
They can have parameters
@Step
public void searches_for(String searchTerms) {
homePage.searchFor(searchTerms);
}
They can be pending
@Pending @Step
public void searches_for(String searchTerms) {
// Not done yet
}
@Step("The carousel should display {0} at a time")
def should_see_a_number_of_visible_ads_in_the_carousel(int adCount) {
assert homePage.visibleCarouselAds.size() == adCount
}
You can customize the title
62. Test Steps To The Rescue!
@Step
def browses_product_categories(String... categories) {
selects_top_level_category(categories.head())
categories.tail().each { subcategory ->
browse_through_subcategory(subcategory)
}
} Steps can call other steps
@Step
def selects_top_level_category(String category) {
homePage.select_top_level_category category
}
@Step
def browse_through_subcategory(subcategory) {
homePage.select_subcategory(subcategory)
}
63. Test Steps To The Rescue!
Test reports document the what and the how
64. Test Steps To The Rescue!
Focus on what we are doing, not how we do it
More reusability
Better reporting
65. Even better with JBehave!
Narrative:
In order to find items more easily
As a customer
I want to be able to browse through the product categories
Scenario: Browse through product categories
Given I am on the home page
When I browse through the product categories Clothing, Mens, Shirts
Then I should see a product with the title 3by3 Milano Stretch Cotton Shirt
JBehave describes what we are doing
Use normal Thucydides steps in the implementation
66. Even better with JBehave!
Narrative:
In order to find items more easily
As a customer
I want to be able to browse through the product categories
Scenario: Browse through product categories
Given I am on the home page
When I browse through the product categories Clothing, Mens, Shirts
Then I should see a product with the title 3by3 Milano Stretch Cotton Shirt
class BrowseByCategorySteps extends BigCommerceJBehaveSteps{
@Steps
CustomerSteps customer; Use normal Thucydides steps
@Given('I am on the home page')
public void givenIAmOnTheHomePage() {
customer.opens_home_page()
}
@When('I browse through the product categories $categories')
public void whenIBrowseThroughTheProductCategories(List<String> categories) {
customer.browses_product_categories(*categories)
}
@Then('I should see a product with the title "$expectedTitle"')
public void thenIShouldSeeAProductWithTheTitle(String expectedTitle) {
customer.should_see_product withTitle(expectedTitle)
}
}
67. Even better with JBehave!
Narrative:
In order to find items more easily
As a customer
I want to be able to browse through the product categories
Context
Scenario: Browse through product categories
Given I am on the home page
When I browse through the product categories Clothing, Mens, Shirts
Then I should see a product with the title 3by3 Milano Stretch Cotton Shirt
What
How
Illustrations
68. Even better with JBehave!
Narrative:
In order to find items more easily
As a customer
I want to be able to browse through the product categories
Scenario: Browse through product categories
Given I am on the home page
When I browse through the product categories Clothing, Mens, Shirts
Then I should see a product with the title 3by3 Milano Stretch Cotton Shirt
Living documentation
Easier to read
Easier to maintain
More work maintaining the .story files
82. Thucydides Fluent Matchers
List<Person> persons = Arrays.asList(new Person("Bill", "Oddie"),
new Person("Tim", "Brooke-Taylor"));
shouldMatch(persons, the("firstName", is(not("Tim"))));
shouldMatch(persons, the("firstName", startsWith("B")));
Matcher work with simple POJOs
83. Thucydides and Tables
import static net.thucydides.core.pages.components.HtmlTable.rowsFrom;
public class SearchResultsPage extends PageObject {
WebElement resultTable;
public SearchResultsPage(WebDriver driver) {
super(driver);
}
public List<Map<String, String>> getSearchResults() {
return rowsFrom(resultTable);
}
}
Convenience methods: convert
a table to a map of Strings
84. Thucydides and Tables
@Test
public void clicking_on_artifact_should_display_details_page() {
developer.opens_the_search_page();
developer.searches_for("Thucydides");
developer.open_artifact_where(the("ArtifactId", is("thucydides")),
the("GroupId", is("net.thucydides")));
developer.should_see_artifact_details_where(the("artifactId", is("thucydides")),
the("groupId", is("net.thucydides")));
}
Using matchers to click on a
row in a table
87. Thucydides Fluent Waits
void addToCart(Integer quantity) {
$(quantitySelection).selectByVisibleText(quantity.toString())
$(addToCart).click()
waitForTextToAppear("added to your cart")
}
A simple wait
void uploadExistingImage(String imageUrl) {
// upload an image
...
waitForPresenceOf(".photo")
}
Wait for an element to be rendered
def waitForPageToLoad() {
waitFor(500).milliseconds()
waitForAbsenceOf("#loading")
}
Wait for an element to disappear
88. Thucydides Fluent Waits
def searchByLocation(postcode) {
element(location).typeAndTab(postcode)
element(locationGo).click()
waitFor("//div[@class='f-item'][contains(.,'${postcode}')]")
}
Waiting for an XPath expression
def filterByLocation(String state) {
element(locationList).click()
waitFor("#location-select li a")
findBy("//span[@id='location-select']//a[contains(.,'$state')]").then().click()
waitForCondition().until(stateIsChosen(state))
} Wait for a non-trivial condition
Function<? super WebDriver, Boolean> stateIsChosen(final String state) {
return new Function<? super WebDriver, Boolean>() {
@Override
Boolean apply(driver) {
return state == getCurrentSelectedState()
};
}
} What are we waiting for
89. Thucydides Asserts
def shouldDisplaySubcategory(subCategory) {
findBy(".SubCategoryList").then(By.linkText(subCategory)).shouldBeCurrentlyVisible()
}
Check that this element is visible
@FindBy(id=”search”)
WebElement searchButton
def searchShouldBeEnabled() {
searchButton.shouldBeCurrentlyEnabled()
}
Check that this element is enabled
93. Nested Finds
public void chooseCategory(String category) {
findBy("//div[@id='category-select']//a[contains(@class,'arrow')]").click();
findBy("//div[@id='category-select']//a[.,contains($category)]").click();
}
Hard to read, hard to maintain
public void chooseCategory(String category) {
findBy("#category-select").then(".arrow").then().click();
findBy("#category-select").then(By.linkText(category)).then().click();
}
A more readable approach