completing the circle - automated web tests as a team communication tool
TRANSCRIPT
As a job seekerI want to find jobs in relevant categoriesSo that I can find a suitable job
User stories
Features/Epics
As a job seekerI want to find jobs in relevant categoriesSo that I can find a suitable job
User stories
☑ The job seeker can see available categories on the home page☑ The job seeker can look for jobs in a given category☑ The job seeker can see what category a job belongs to
Acceptance criteria
As a job seekerI want to find jobs in relevant categoriesSo that I can find a suitable job
User stories
☑ The job seeker can see available categories on the home page☑ The job seeker can look for jobs in a given category☑ The job seeker can see what category a job belongs to
scenario "A job seeker can see the available job categories on the home page",{ when "the job seeker is looking for a job", then "the job seeker can see all the available job categories"}
Automated acceptance test
Acceptance criteria
scenario "A job seeker can see the available job categories on the home page",{ when "the job seeker is looking for a job", then "the job seeker can see all the available job categories"}
Implemented development tests Implemented acceptance tests
Automated acceptance test
Technical tests are for the dev team
Not All Web Tests are Acceptance Tests
Acceptance tests are for everyone else
Technical tests talk to the dev team
Acceptance tests talk to everyone else
Not All Web Tests are Acceptance Tests
A sample Page Object
lookForJobsWithKeywords(values : String)getJobTitles() : List<String>
FindAJobPage
A Page Object
A sample Page Object
public class FindAJobPage extends PageObject {
WebElement keywords; WebElement searchButton;
public FindAJobPage(WebDriver driver) { super(driver); }
public void lookForJobsWithKeywords(String values) { typeInto(keywords, values); searchButton.click(); }
public List<String> getJobTitles() { List<WebElement> tabs = getDriver() .findElements(By.xpath("//div[@id='jobs']//a")); return extract(tabs, on(WebElement.class).getText()); }}
An implemented Page Object
A sample Page Object
public class WhenSearchingForAJob {
@Test public void searching_for_a_job_should_display_matching_jobs() { FindAJobPage page = new FindAJobPage(); page.open("http://localhost:9000"); page.lookForJobsWithKeywords("Java"); assertThat(page.getJobTitles(), hasItem("Java Developer")); }}
A test using this Page Object
scenario "A job seeker can see the available job categories on the home page",{ when "the job seeker is looking for a job", then "the job seeker can see all the available job categories"}
Automated
scenario "The user can see the available job categories on the home page",{ when "the job seeker is looking for a job", { job_seeker.open_jobs_page() } then "the job seeker can see all the available job categories", { job_seeker.should_see_job_categories "Java Developers", "Groovy Developers" }}
Implemented
JobSeekerSteps
open_jobs_page()should_see_job_categories(String... categories)...
JobSeekerSteps
open_jobs_page()should_see_job_categories(String... categories)...
JobSeekerSteps
open_jobs_page()should_see_job_categories(String... categories)...
Step libraries
scenario "The user can see the available job categories on the home page",{ when "the job seeker is looking for a job", { job_seeker.open_jobs_page() } then "the job seeker can see all the available job categories", { job_seeker.should_see_job_categories "Java Developers", "Groovy Developers" }}
JobSeekerSteps
open_jobs_page()should_see_job_categories(String... categories)...
JobSeekerSteps
open_jobs_page()should_see_job_categories(String... categories)...
JobSeekerSteps
open_jobs_page()should_see_job_categories(String... categories)...
Step libraries
Page Objects
Implemented Tests
Webdriver/Selenium 2 extension
Organize tests, stories and features
Measure functional coverage
Record/report test execution
Defining your acceptance tests
scenario "The administrator deletes a category from the system",{ given "a category needs to be deleted", when "the administrator deletes a category", then "the system will confirm that the category has been deleted", and "the deleted category should no longer be visible to job seekers",}
focus on business value
scenario "The administrator adds a new category to the system",{ given "a new category needs to be added to the system", when "the administrator adds a new category", then "the system should confirm that the category has been created", and "the new category should be visible to job seekers",}
...defined in business terms
scenario "A job seeker can see the available job categories on the home page",
{ when "the job seeker is looking for a job", then "the job seeker can see all the available job categories"}
High level requirements...
Organizing your requirements
public class Application {
@Feature public class ManageCompanies { public class AddNewCompany {} public class DeleteCompany {} public class ListCompanies {} }
@Feature public class ManageCategories { public class AddNewCategory {} public class ListCategories {} public class DeleteCategory {} }
@Feature public class BrowseJobs { public class UserLookForJobs {} public class UserBrowsesJobTabs {} }}
Features
Stories
Implementing your acceptance testsusing "thucydides"thucydides.uses_steps_from AdministratorStepsthucydides.uses_steps_from JobSeekerStepsthucydides.tests_story AddNewCategory
scenario "The administrator adds a new category to the system",{ given "a new category needs to be added to the system", { administrator.logs_in_to_admin_page_if_first_time() administrator.opens_categories_list() } when "the administrator adds a new category", { administrator.selects_add_category() administrator.adds_new_category("Scala Developers","SCALA") } then "the system should confirm that the category has been created", { administrator.should_see_confirmation_message "The Category has been created" } and "the new category should be visible to job seekers", { job_seeker.opens_jobs_page() job_seeker.should_see_job_category "Scala Developers" }}
We are testing this story
Narrative style
Step through an example
An acceptance criteria
Still high-level
Some folks prefer JUnit...@RunWith(ThucydidesRunner.class)@Story(AddNewCategory.class)public class AddCategoryStory {
@Managed public WebDriver webdriver;
@ManagedPages(defaultUrl = "http://localhost:9000") public Pages pages;
@Steps public AdministratorSteps administrator;
@Steps public JobSeekerSteps job_seeker;
@Test public void administrator_adds_a_new_category_to_the_system() { administrator.logs_in_to_admin_page_if_first_time(); administrator.opens_categories_list(); administrator.selects_add_category(); administrator.adds_new_category("Java Developers","JAVA"); administrator.should_see_confirmation_message("The Category has been created");
job_seeker.opens_job_page(); job_seeker.should_see_job_category("Java Developers"); }
@Pending @Test public void administrator_adds_an_existing_category_to_the_system() {}}
Thucydides handles the web driver instances
Using the same steps
Tests can be pending
Defining your test stepspublic class AdministratorSteps extends ScenarioSteps {
@Step public void opens_categories_list() { AdminHomePage page = getPages().get(AdminHomePage.class); page.open(); page.selectObjectType("Categories"); }
@Step public void selects_add_category() { CategoriesPage categoriesPage = getPages().get(CategoriesPage.class); categoriesPage.selectAddCategory(); }
@Step public void adds_new_category(String label, String code) { EditCategoryPage newCategoryPage = getPages().get(EditCategoryPage.class); newCategoryPage.saveNewCategory(label, code); }
@Step public void should_see_confirmation_message(String message) { AdminPage page = getPages().get(AdminPage.class); page.shouldContainConfirmationMessage(message); }
@StepGroup public void deletes_category(String name) { opens_categories_list(); displays_category_details_for(name); deletes_category(); }}
A step library
High level steps...
...implemented with Page Objects
...or with other steps
Defining your page objectspublic class EditCategoryPage extends PageObject {
@FindBy(id="object_label") WebElement label;
@FindBy(id="object_code") WebElement code;
@FindBy(name="_save") WebElement saveButton;
public EditCategoryPage(WebDriver driver) { super(driver); }
public void saveNewCategory(String labelValue, String codeValue) { typeInto(label, labelValue); typeInto(code, codeValue); saveButton.click(); }}
Provides some useful utility methods...
but otherwise a normal WebDriver Page Object
Data-driven testing
categories.csv
public class DataDrivenCategorySteps extends ScenarioSteps { public DataDrivenCategorySteps(Pages pages) { super(pages); }
private String name; private String code;
@Steps public AdminSteps adminSteps;
public void setCode(String code) {...} public void setName(String name) {...}
@Step public void add_a_category() { adminSteps.add_category(name, code); }}
Test data
Test steps
Data-driven testing
categories.csv
public class DataDrivenCategorySteps extends ScenarioSteps { public DataDrivenCategorySteps(Pages pages) { super(pages); }
private String name; private String code;
@Steps public AdminSteps adminSteps;
public void setCode(String code) {...} public void setName(String name) {...}
@Step public void add_a_category() { adminSteps.add_category(name, code); }}
@Steps public DataDrivenCategorySteps categorySteps;
@Test public void adding_multiple_categories() throws IOException { steps.login_to_admin_page_if_first_time(); steps.open_categories_list();
withTestDataFrom("categories.csv").run(categorySteps).add_a_category(); }
Test data
Test steps
Call this step for each row
The Circle is CompleteAutomated web tests as a team communication tool
John Ferguson SmartEmail: [email protected]: hCp://www.wakaleo.com
TwiCer: wakaleo