Date post: | 05-Dec-2014 |
Category: |
Education |
Upload: | yasha-kramarenko |
View: | 1,122 times |
Download: | 6 times |
Conventions :)
● Sympathy colors***:
Green =
Orange =
Red =
*** often are subjective and applied to specific context ;)
● At project with no Web UI automation, no unit testing
● With 4(5) Manual QA
– Using checklists + long detailed End to End test cases
● With 1 QA Automation found
Testing single page web app
● Ajax
● only <div>, <a>, <input>
– Inconsistent implementation
● No confident urls
● One current Frame/Page with content per user step
– Deep structure: ● Authorization > Menus > SubMenus > Tabs > Extra > Extra
– Modal dialogs
Met Requirements
● Automate high level scenarios
– use AC from stories
– existed Manual Scenarios
● Use 3rd party solutions
– Java Desired
● Involve Manual QA
– provide easy to use solution
– BDD Desired
● In Tough Deadlines :)
Dreaming of framework...● Fast in development
– Using instruments quite agile to adapt to project specifics
● Extremely easy to use and learn
● Simple DSL for tests
● BDD – light and DRY as much as possible
“Raw” Webdriver with tunings (HtmlElements, Matchers, etc.)
● No convenient and concise Ajax support out of the box
● Code redundancy
– Driver creation
– Finding elements
– Assert element states
● Harmcrest Matchers are easy, but assertThat() knows nothing about Ajax
– HtmlElements gives powerful but bulky “waiting” decorators (see links [1][2])
Concordion
● Hard to extend
– Custom commands (asserts)
<html xmlns:concordion="http://www.concordion.org/2007/concordion"> <body> <p concordion:assertEquals="getGreeting()">Hello World!</p> </body></html>
Thucydides
● No convenient Ajax support
– Asserts and Conditions are bound● Hard to extend
● Framework, not a Lib
– Not agile● It's hard to use some patterns (e.g. LoadableComponent)
● Monstrous Manual :)
= Redundancy
Not BDD
Easy:) Instruments
@Test
public void userCanLoginByUsername() {
open("/login");
$(By.name("user.name")).setValue("johny");
$("#submit").click();
$(".loading_progress").should(disappear);
$("#username").shouldHave(text("Hello, Johny!"));
}
Selenide Pros● Wrapper over Selenium with Concise API
● Lib, not a Framework
– You still have your raw WebDriver when needed
● should style asserts
– Independent from Conditions
– Waiting for conditions (Ajax friendly)
● Screenshot reporting on each failed should
● Screenshot API
– Providing screenshots' context
– Get all screenshots for context
● Actively supported by authors
Killer FeatureSelenide Conditions
public static final Condition checked = new Condition("checked") {
@Override
public boolean apply(WebElement element) {
return isChecked(element);
}
@Override
public String actualValue(WebElement element) {
return isChecked(element) ? "checked" : "unchecked";
}
@Override
public String toString(){
return "checked";
}
};
Or even shorter
public static final Condition checked = new Condition("checked") {
@Override
public boolean apply(WebElement element) {
return isChecked(element);
}
};
Custom Condition Examples
Aliases
Implementation
public static final Condition checked =
Condition.hasClass("checked");
public static final Condition enabled =
Condition.hasNotClass("disabled");
public static final Condition expanded =
Condition.attribute("area-expanded", "true");
Usage
showPasswordCheckBox().shouldBe(not(checked));
applyButton().shouldBe(enabled);
treeItem.shouldBe(expanded);
Usage: is
public static void ensureExpanded(SelenideElement item){
if (item.is(not(expanded))){
expand(item); }}
Own implementation
Implementation (1)public static final Condition inRadioMode(final String radioMode){ return new Condition("in radio mode: " + radioMode) { @Override public boolean apply(WebElement webElement) {
boolean res = true; for(WebElement mode: Mode.modes(webElement)){
if (Mode.value(mode).equals(radioMode)){ res = res &&
mode.getAttribute("class").contains("active"); } else { res = res && !
mode.getAttribute("class").contains("active"); } } return res; } };}
Implementation (2)
public static final Condition faded = new Condition("faded with backdrop") {
@Override public boolean apply(WebElement element) {
return backDropFor(element).exists(); }};
Implementation (3)
public static Condition leftSliderPosition(final Integer position)
{
return new Condition("left slider position " + position)
{ @Override public boolean apply(WebElement webElement) {
return
getLeftSliderCurrentPosition(webElement).equals(position); } };}
Usage
tabContainer().shouldBe(faded);
accessRadioButtons().shouldBe(inRadioMode(PRIVATE));
scheduler.shouldHave(leftSliderPosition(100));
Composition*
* public static final will be omitted for simplicity
ImplementationCondition loadingDialog = condition(loadingDialog(), exist);Condition applyButtonDisabled = condition(primeBtn(), disabled);Condition cancelButtonDisabled = condition(scndBtn(), disabled);
Condition processed = with_(no(Modal.dialog()));Condition loaded = and(processed, with_(no(loadingDialog)), with_(applyButtonDisabled));
Condition savedForSure = and(loaded, with_(saveSuccessMsg()));
Condition failedToSave = and( processed, with_(no(loadingDialog)), with_(not(applyButtonDisabled)), with_(no(saveSuccessMsg())), with_(not(cancelButtonDisabled)), with_(saveErrorsMsg()));
Usage
//fill page with valid/invalid data...
Page.save()
Page.shouldBe(and( failedToSave, with(usernameValidation(), currentPassValidation()), with(no(newPassValidation(), matchPassValidation()))))
//fix errors and save...
Page.shouldBe(savedForSure)
Selenide Cons
● Young:)
– Many things can be improved● Error messages● Condition helpers● Screenshot API
– Tones of them have been resolved so far
– Others can be implemented as your own extensions
● Not all-powerfull
– For some things you will still need raw WebDriver
Easyb Pros● Gherkin (given/when/then) and its implementation live at
the same file
– better maintainability
– more DRY code
● no implementation => “pending” test
● simple but nice looking reports
● groovy as a script language for tests
– scenarios are ordered
Easyb Cons
● bad support of framework from authors.● some features are broken
– before_each
● no tags per scenario/step– only tags per story
● Stack trace of error messages is clipped● No out of the box way to put listeners on
steps/scenarios● “Shared steps” feature is present but not quite
handy
Easyb Selenide Integration
Problem Selenide shoulds vs Easyb shoulds
Easyb catches any 'should' (shouldBe, shouldHave, ...) except “should” and “shouldNot”
showPasswordCheckBox().shouldNot(checked);
//Less readable:(
Solution => Decorators
showPasswordCheckBox().shouldNot(be(checked));
showPasswordCheckBox().should(be(not(checked)));
All Together :)
Preconditions to BDD
● PO knows what is Criteria of Good Requirement
● Manual QA knows how to write “Automatable” Scenarios
Team is competent :)
Pending Easyb Story by PO
description "Products List page"
scenario "Add new product", {
given "On Products List page"
then "new product can be added"
}
Pending Detailed Easyb Story by Manual QA
description "Products List page"
scenario "Add new product", {
given "On Products List page"
and "No custom product with 'Product_1' name exist"
then "new product with 'Product_1' name can be added"
and "after relogin still present"
}
Implemented Easyb Storydescription "ProductsList test"tags "functional"BaseTest.setup() scenario "Add new product", { given "On ProductsList page",{ ProductsList.page().get() } and "No custom product with '" + TEST_PRODUCT + "' name exist", { Table.ensureHasNo(cellByText(TEST_PRODUCT)) } then "new product with '" + TEST_PRODUCT + "' name can be added", { ProductsList.addProductForSure(TEST_PRODUCT) } and "after relogin still present", { cleanReLogin() Table.cellByText(TEST_PRODUCT).should(be(visible)); }}
Easyb Report
FailedEasyb Report
Alternative: TestNG testpublic class ProductManagement extends AbstractTest {
@Test
public void testNewProductCanBeAdded() {
ProductsList.page().get();
Table.ensureHasNo(cellByText(TEST_PRODUCT));
ProductsList.addProductForSure(TEST_PRODUCT);
cleanReLogin();
Table.cellByText(TEST_PRODUCT).should(Be.visible);
}
}
Alternative: TestNG Report
Failed TestNG Report
When Easyb ?
● Detailed reporting of test steps
● Ordered tests execution (as present in the file)
● “Somebody” wants Gherkin
– Automation resources are limited, and help may come from PO or Manual QA providing detailed 'steps to code'
When TestNG/Junit ?
● When you have strong 'agile' devs/automation which know why what and how to test and do write tests.
– Hence you never need pretty looking reports to please your manager customer because you just have high quality product.
Ideas for improvements
● Kill Kenny
– if he is the only who wants Gherkin:)
– and stay KISS with TestNG/Junit
● Contribute to Easyb:)
● Bless Selenide:)
– Authors will contribute nevertheless
Q&A
Resources, Links
● Src of example test framework: https://github.com/yashaka/gribletest
● Application under test used in easyb examples: http://grible.org/download.php
● Instruments
– http://selenide.org/
– http://easyb.org/
● To Artem Chernysh for implementation of main base part of the test framework for this presentation
– https://github.com/elaides/gribletest● To Maksym Barvinskyi for application under test
– http://grible.org/● To Andrei Solntsev, creator of Selenide, for close
collaboration on Selenide Q&A, and new features implemented:)
Contacts
● skype: yashaolin
● http://www.linkedin.com/in/iakivkramarenko