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

[SeleniumCamp] How to make your test automation Groovier

By Sergey Pirogov

[SeleniumCamp] How to make your test automation Groovier

  • 2,120