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?
We want effective Java Test Automation!
Boilerplate
What's the problem?
We live in dynamic world
We test dynamic web applications
Time to use dynamic languages!
Groovy = Java
+ optional typing
+ closures
+ metaprogramming
+ scripting
+ GDK library
- boilerplate
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 books = 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
Groovy Sshoogr
https://github.com/aestasit/sshoogr
@Grab('com.aestasit.infrastructure.sshoogr:sshoogr:0.9.18')
import static com.aestasit.infrastructure.ssh.DefaultSsh.*
remoteSession('user2:654321@localhost:2222') {
exec 'rm -rf /tmp/*'
exec 'touch /var/lock/my.pid'
remoteFile('/var/my.conf').text = "enabled=true"
def file = "/root/home/test.txt"
def selenium = "selenium-server-standalone-2.48.2.jar"
//read from file
print remoteFile(file).text
//copy file to remote host
scp {
from { localFile "/root/home/${selenium}"}
into { remoteFile "/root/remote/${selenium}" }
}
}
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"}
}
http://automation-remarks.com/groovy-page/
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
[QA Conf] How to make your test automation Groovier
By Sergey Pirogov
[QA Conf] How to make your test automation Groovier
- 1,315