Make Your Test Automation Groovier
Sergey Pirogov
Sergey Pirogov
    Senior Software
    Test Automation Engineer
    EPAM Systems
    
    skills: ['Java' , 'Groovy']
    blog: http://automation-remarks.com
    twitter: @s_pirogov
    conference: QA Fest, SQA days, SeleniumCamp    

Is your test automation written in statically compiled language?

How to provide solutions faster?
How to make test automation more effective?
How to reduce time for maintanace ?
Often asked questions

We live in dynamic world
We test dynamic web applications
Time to use dynamic languages!
Dynamic languages pros
- More Concise
- Faster turnaround
- Monkey patching
- Duck typing
- Easier to learn
GROOVY
- Got best from Python, Ruby, Smalltalk, JavaScript
- JVM Platform language
- Object Oriented
- Optionally typed
- 100% Java compatible
- Scripting
- Runtime metaprogramming
- Can compile statically
- Groovy Console
Java Assert
assertEquals(person.getAccountName(accounNumber), "AC1220");org.junit.ComparisonFailure: 
Expected :AC[20]0
Actual   :AC[122]0
assert person.getAccountName(accounNumber) == "AC1220"Caught: Assertion failed: 
assert person.getAccountName(accounNumber) == "AC1220"
       |      |              |             |
       |      AC200          |             |
       |                    100           false
       Person("Ivan", 12)Groovy Assert

Java SoftAssert
check {
    softly { assert frodo.name == "Frodo" }
    softly { assert frodo.race == "Hobbit" }
}SoftAssertions softly= new SoftAssertions();
softly.assertThat(frodo.getName()).isEqualTo("Frodo");
softly.assertThat(frodo.getRace()).is("Hobbit");
softly.assertAll();Groovy SoftAssert
<response version-api="2.0">
        <value>
            <books>
                <book available="20" id="1">
                    <title>Don Xijote</title>
                    <author id="1">Manuel De Cervantes</author>
                </book>
                <book available="14" id="2">
                    <title>Catcher in the Rye</title>
                   <author id="2">JD Salinger</author>
               </book>
               <book available="13" id="3">
                   <title>Alice in Wonderland</title>
                   <author id="3">Lewis Carroll</author>
               </book>
               <book available="5" id="4">
                   <title>Don Xijote</title>
                   <author id="4">Manuel De Cervantes</author>
               </book>
           </books>
       </value>
    </response>Parse XML
Java way

org.jdom.input.SAXBuilder saxBuilder = new SAXBuilder();
try {
    org.jdom.Document doc = saxBuilder.build(new StringReader(xml));
    String message = doc.getRootElement().getText();
    System.out.println(message);
} catch (JDOMException e) {
    // handle JDOMException
} catch (IOException e) {
    // handle IOException
}
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = null;
try {
    db = dbf.newDocumentBuilder();
    InputSource is = new InputSource();
    is.setCharacterStream(new StringReader(xml));
    try {
        Document doc = db.parse(is);
        String message = doc.getDocumentElement().getTextContent();
        System.out.println(message);
    } catch (SAXException e) {
        // handle SAXException
    } catch (IOException e) {
        // handle IOException
    }
} catch (ParserConfigurationException e1) {
    // handle ParserConfigurationException
}def response = new XmlSlurper().parseText(xml)Groovy XML
<book available="20" id="1">
    <title>Don Xijote</title>
    <author id="1">Manuel De Cervantes</author>
</book>def title = books.book.find { it.author.@id == 1 }.title
Map Pain
Map<Integer,Person> map = new HashMap<>();
map.put(1, new Person("Ivan", 23));
map.put(2, new Person("Dima", 12));
map.put(3, new Person("Vlad", 34));
map = [1: new Person("Ivan", 23), 2: new Person("Dima", 12), 3: new Person("Vlad", 34)]Map<Integer, Person> persons =
                map.entrySet()
                        .stream()
                        .filter(m -> m.getValue().getAge() > 18)
                        .collect(Collectors.toMap(m -> m.getKey(), m -> m.getValue()));map.findAll { it.value.age > 18 }Filter Map
Groovy way
Properties as a code
browser = 'firefox'
emails = [from: 'director', to: 'accountant']
environments {
    dev {
        host = "devthost"
    }
    test {
        host = "testhost"
        browser = 'ie'
    }
}Config.groovy
This is CODE
Groovy Configuration
def config = new ConfigSlurper("dev").parse(Config)
assert config.host == "devhost"
assert config.browser == "firefox"
assert config.emails.from == "director"
assert config.emails.to == "accountant"Flexible and elegant
Canonical PageObject
public class MainPage extends PageObject {
    @FindBy(linkText = ".all")
    WebElement allbooksButton;
    @FindBy(linkText = ".search")
    WebElement searchButton;
    @FindBy(name = "query")
    WebElement searchField;
    @FindBy(css = "button")
    WebElement searchBegin;
    public BookPage(WebDriver driver) {
        super(driver);
    }
Groovy PageObject
class MainPage extends Page {
    
}static url = "http://ukr.net"
static content = {
     loginInput {$ ".loginForm input"}
     passwordInput { $ ".password input"}
     submit {$ ".submit button"}
     error {$ ".error-text"}
}
Groovy Page Component
//DeclareComponent
class LoginForm extends Page {
    static content = {
         loginInput {$ ".loginForm input"}
         passwordInput { $ ".password input"}
         submit {$ ".submit button"}
         error {$ ".error-text"}
    }
    def login(String name,String password){
        loginInput << name
        passwordInput << password
        submit.click()
    }
}Groovy Page vs Component
class MainPage extends Page {
    @Component
    LoginFrom loginForm
}Page object become tiny

As a Result
Team efficiency increased twice
We stoped writing boilerplate
Readable and maintainable tests
def "shouldBeLoginError"() { 
  MainPage mainPage = go MainPage
  mainPage.loginForm.login("test","test")
  assert mainPage.loginForm.errorText == "Wrong credentials"
}But not everything is so good!
- Runtime bugs
- Less performant
- IDE support
Groovy works 10% slower than Java
But it the same as Python, Ruby, PHP...
Moreover you can easily speed up with @CompileStatic
Use power of Intelij Idea to support dynamics
Be dynamic
Build your test automation with Groovy !
Thank you!
twitter: @s_pirogov
blog: http://automation-remarks.com