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,204