SlideShare ist ein Scribd-Unternehmen logo
1 von 42
SCULPT! YOUR! TESTS!
Taras Oleksyn
 4+ years of test automation experience
(in company, freelance)
 Enjoys building simple and elegant
solutions
 Has beautiful eyes
READABILITY
more than 70% of a developers time is spend
reading and understanding code*
*https://blogs.msdn.microsoft.com/peterhal/2006/01/04/what-do-programmers-really-do-anyway-aka-part-2-of-the-yardstick-saga/
 Tuning your language
extension libraries
new features
 Readable web UI test stack
 Sculpting! Your! Tests!
WE’LL TALK:
LOMBOK
both beautiful island in Indonesia and
awesome Java extension library
https://projectlombok.org/
TYPE INFERENCE
automatic deduction of the data type of an
expression
LOCAL VARIABLE TYPE INFERENCE
boolean isRemoteEnabled = true;
final String browser = getProperty("browser", "FIREFOX");
final ArrayList<ProductType> productTypeList = new ArrayList<>();
var isRemoteEnabled = true;
val browser = getProperty("browser", "FIREFOX");
val productTypeList = new ArrayList<ProductType>();
TYPE INFERENCE
val – final local variable
var – non-final local variable
works on:
local variables
loop scope variables
https://habrahabr.ru/post/280075/
http://openjdk.java.net/jeps/286
POJO
public AutomationEngineer(String name,
boolean likesToBuildFrameworks,
boolean hatesBDD) {
this.name = name;
this.likesToBuildFrameworks = likesToBuildFrameworks;
this.hatesBDD = hatesBDD;
}
public class AutomationEngineer {
…
private final String name;
private final boolean likesToBuildFrameworks;
private final boolean hatesBDD;
public String getName() {return name;}
public boolean hatesBDD() { return hatesBDD; }
public boolean likesToBuildFrameworks() { … }
@Override
public boolean equals(Object o) { … }
@Override
public int hashCode() { … }
@Override
public String toString() { … }
}
POJO
LOMBOK
public class AutomationEngineer {
private final String name;
private final boolean likesToBuildFrameworks;
private final boolean hatesBDD;
}
@Data
public enum State {
ALABAMA("AL", 1),
ALASKA("AK", 2),
ARIZONA("AZ", 3),
CALIFORNIA("CA", 4);
private final String shortName;
private final int stateIndex;
}
LOMBOK
State(String shortName, int stateIndex) {
this.shortName = shortName;
this.stateIndex = stateIndex;
}
public String getShortName() { return shortName; }
public int getStateIndex() { return stateIndex; }
}
@Getter
@RequiredArgsConstructor
EXTENSION METHOD
a method added to an object after the original
object was compiled
EXTENSION METHOD
new ChromeDriver()
.getClickableElement(By.id("some_id"))
.click();
new ChromeDriver()
.findElement(By.id("some_id"))
.click();
EXTENSION METHOD
public class WebElementExtension {
public static WebElement getClickableElement(WebDriver driver, By by){
return new WebDriverWait(driver, 30)
.until(ExpectedConditions.elementToBeClickable(by));
}
}
@ExtensionMethod(WebElementExtension.class)
public class ExtensionMethodExample {
@Test
void testDriverExtension(){
new ChromeDriver()
.getClickableElement(By.id("some_id"))
.click();
}
}
LOMBOK
@Value
@Builder
@Accessors
@UtilityClass
…
VAVR (EX JAVASLANG)
functional library for Java 8+ to reduce the amount
of code and to increase the robustness
http://blog.vavr.io/
PATTERN MATCHING
act of checking a given sequence for the
presence of the constituents of some pattern
http://cr.openjdk.java.net/~briangoetz/amber/pattern-match.html
PLAIN JAVA
public void filterUsersBy(UserType user) {
WebElement userLocator;
switch (user) {
case ADMIN:
userLocator = adminUserLocator; break;
case MEMBER:
userLocator = memberUserLocator; break;
case VENDOR:
userLocator = vendorUserLocator; break;
default:
userLocator = superAdminLocator; break;
}
select(userLocator);
click(filterButton);
}
public void filterUsersBy(UserType user) {
val userLocator = Match(user).of(
Case($(ADMIN), adminUserLocator),
Case($(MEMBER), memberUserLocator),
Case($(VENDOR), vendorUserLocator),
Case($(), superAdminLocator)
);
select(userLocator);
click(filterButton);
}
VAVR
public void doActionFor(UserType user) {
Match(user).of(
Case(isIn(ADMIN, SUPER_ADMIN), obj -> run(this::selectAdminUser)),
Case($(MEMBER), obj -> run(this::selectMemberUser)),
Case($(), obj -> {throw new SomeException("Invalid user: “ + obj);})
);
}
VAVR
OWNER
library for getting rid of the boilerplate code in
properties based configuration
http://owner.aeonbits.org/
PROPERTY
BrowserSetting.properties:
browserName=firefox
version=57
platform=LINUX
javascriptEnabled=true
acceptSslCerts=false
isRemote=true
public interface BrowserSetting extends Config {
String browserName();
String version();
Platform platform();
boolean isRemote();
boolean javascriptEnabled();
boolean acceptSslCerts();
}
OWNER
BrowserSetting.properties:
browserName=firefox
version=57
platform=WINDOWS
isRemote=true
javascriptEnabled=true
acceptSslCerts=false
OWNER
browserSetting.browserName();
browserSetting.platform();
browserSetting.version();
browserSetting.isRemote();
browserSetting.javascriptEnabled();
browserSetting.acceptSslCerts();
val browserSetting = ConfigFactory.create(BrowserSetting.class);
OWNER
@Key("browser.name")
@DefaultValue("FIREFOX")
@HotReload
@Sources({
"file:BrowserSetting.properties",
"classpath:BrowserSetting.properties"})
…
@
public List<Product> getProductsFor(ProductCategory category) {
return filteredProducts;
}
JAVA
List<WebElement> products = getVisibleElementsFor(productsLocator);
List<Product> filteredProducts = new ArrayList<>();
for (WebElement productElement : products) {
String productName = productElement.getText();
String productCategory = getCategoryFrom(productName);
}
if (productCategory.equals(category)) {
Product product = new Product(productName);
filteredProducts.add(product);
}
public List<Product> getProductsFor(ProductCategory category) {
return getVisibleElementsFor(productsLocator)
.stream()
.map(WebElement::getText)
.filter(productName ->
getCategoryFrom(productName).equals(category))
.map(Product::new)
.collect(toList());
}
JAVA 8
Gradle
TestNG
Selenide Allure AssertJ
DSL layer
Selenium Grid/Selenoid
TO GO STACK
API
SELENIDE
WebDriverManager
ThreadLocal static instance
SelenideElement
built-in smart waits
file uploads
…
maintain browser drivers
manage WebDriver
instance
UI mapping
wait strategies
assertions
…
ASSERTJ
void verifyAddingApplicant() {
…
assertTrue("John Smith".equals(applicant.getName()),
"Failed to update applicant name");
…
assertTrue(applicantsTable.getRecordsCount() == 1,
“Applicants table has more than 1 record");
}
void verifyAddingApplicant() {
…
assertThat(applicant).hasName(“John Smith“);
…
assertThat(applicantsTable).hasRecords(1);
}
CUSTOM ASSERT
public class ApplicantAssert
extends AbstractAssert<ApplicantAssert, ApplicantInfo> {
public ApplicantAssert(ApplicantInfo actual) {
super(actual, ApplicantAssert.class);
}
public static ApplicantAssert assertThat(ApplicantInfo actual) {
return new ApplicantAssert(actual);
}
public ApplicantAssert hasName(String name) {
...
}
}
SCULPTING! YOUR! TESTS!
extending language with libraries
using new language features
using ready solutions
building concise DSL
void testAddingApplicant() {
final ApplicantInfo applicant = getApplicantInfo();
final EducationInfo education = getEducationInfo();
applicantsPage
.startAddingApplicant()
.fillAllFieldsWith(applicant)
.startAddingInfo(ApplicantInfoType.EDUCATION)
.fillAllFieldsWith(education)
.saveApplicant();
assertTrue(applicantsPage.getApplicantAddedMessage().isDisplayed(),
"Failed to add new applicant");
}
1
2
3
final ApplicantInfo applicant = getApplicantInfo();
final EducationInfo education = getEducationInfo();
assertThat(applicantsPage).applicantAdded();
applicantsPage
.startAddingApplicant()
.fillAllFieldsWith(applicant)
.startAddingInfo(ApplicantInfoType.EDUCATION)
.fillAllFieldsWith(education)
.saveApplicant();
assertTrue(applicantsPage
.getApplicantAddedMessage().isDisplayed(),
"Failed to add new applicant");
val applicant = getApplicantInfo();
val education = getEducationInfo();
applicantsPage
.add(applicant)
.addInfo(education)
.saveApplicant();
void testAddingApplіcant() {
val applicant = getApplicantInfo();
val education = getEducationInfo();
applicantsPage
.add(applicant)
.addInfo(education)
.saveApplicant();
assertThat(applicantsPage).applicantAdded();
}
void testAddingApplicant() {
final ApplicantInfo applicant = getApplicantInfo();
final EducationInfo education = getEducationInfo();
applicantsPage
.startAddingApplicant()
.fillAllFieldsWith(applicant)
.startAddingInfo(ApplicantInfoType.EDUCATION)
.fillAllFieldsWith(education)
.saveApplicant();
assertTrue(applicantsPage.getApplicantAddedMessage().isDisplayed(),
"Failed to add new applicant");
}
ADVANTAGES ?
decreased code base
increased code readability
time saved for adding actual value
…
DOWNSIDES ?
learning curve
complexity increases
external risks
…
Thank You!
HOW TO PRONOUNCE ?
[SUITE] pronounced like
Jason[JSON]
[LINUX] pronounced
sweet
pronounced like the name
[leenooks]

Weitere ähnliche Inhalte

Was ist angesagt?

Was ist angesagt? (20)

Activator and Reactive at Play NYC meetup
Activator and Reactive at Play NYC meetupActivator and Reactive at Play NYC meetup
Activator and Reactive at Play NYC meetup
 
ERRest - The Next Steps
ERRest - The Next StepsERRest - The Next Steps
ERRest - The Next Steps
 
Taming Core Data by Arek Holko, Macoscope
Taming Core Data by Arek Holko, MacoscopeTaming Core Data by Arek Holko, Macoscope
Taming Core Data by Arek Holko, Macoscope
 
Hibernate
Hibernate Hibernate
Hibernate
 
1 aleksandr gritsevski - attd example using
1   aleksandr gritsevski - attd example using1   aleksandr gritsevski - attd example using
1 aleksandr gritsevski - attd example using
 
JavaExamples
JavaExamplesJavaExamples
JavaExamples
 
Apache Utilities At Work V5
Apache Utilities At Work   V5Apache Utilities At Work   V5
Apache Utilities At Work V5
 
Pragmatic unittestingwithj unit
Pragmatic unittestingwithj unitPragmatic unittestingwithj unit
Pragmatic unittestingwithj unit
 
ShmooCon 2009 - (Re)Playing(Blind)Sql
ShmooCon 2009 - (Re)Playing(Blind)SqlShmooCon 2009 - (Re)Playing(Blind)Sql
ShmooCon 2009 - (Re)Playing(Blind)Sql
 
Good Practices On Test Automation
Good Practices On Test AutomationGood Practices On Test Automation
Good Practices On Test Automation
 
Http4s, Doobie and Circe: The Functional Web Stack
Http4s, Doobie and Circe: The Functional Web StackHttp4s, Doobie and Circe: The Functional Web Stack
Http4s, Doobie and Circe: The Functional Web Stack
 
Core Java - Quiz Questions - Bug Hunt
Core Java - Quiz Questions - Bug HuntCore Java - Quiz Questions - Bug Hunt
Core Java - Quiz Questions - Bug Hunt
 
Bring the fun back to java
Bring the fun back to javaBring the fun back to java
Bring the fun back to java
 
SAP Testing Training
SAP Testing TrainingSAP Testing Training
SAP Testing Training
 
JS and patterns
JS and patternsJS and patterns
JS and patterns
 
Unit/Integration Testing using Spock
Unit/Integration Testing using SpockUnit/Integration Testing using Spock
Unit/Integration Testing using Spock
 
Jdbc
JdbcJdbc
Jdbc
 
Sql Injection Myths and Fallacies
Sql Injection Myths and FallaciesSql Injection Myths and Fallacies
Sql Injection Myths and Fallacies
 
Testing in android
Testing in androidTesting in android
Testing in android
 
Rhino Mocks
Rhino MocksRhino Mocks
Rhino Mocks
 

Ähnlich wie Тарас Олексин - Sculpt! Your! Tests!

Laurens Van Den Oever Xopus Presentation
Laurens Van Den Oever Xopus PresentationLaurens Van Den Oever Xopus Presentation
Laurens Van Den Oever Xopus Presentation
Ajax Experience 2009
 
Overview of Android Infrastructure
Overview of Android InfrastructureOverview of Android Infrastructure
Overview of Android Infrastructure
Alexey Buzdin
 
Overview of Android Infrastructure
Overview of Android InfrastructureOverview of Android Infrastructure
Overview of Android Infrastructure
C.T.Co
 
Ajax Fundamentals Web Applications
Ajax Fundamentals Web ApplicationsAjax Fundamentals Web Applications
Ajax Fundamentals Web Applications
dominion
 

Ähnlich wie Тарас Олексин - Sculpt! Your! Tests! (20)

[@IndeedEng] Building Indeed Resume Search
[@IndeedEng] Building Indeed Resume Search[@IndeedEng] Building Indeed Resume Search
[@IndeedEng] Building Indeed Resume Search
 
比XML更好用的Java Annotation
比XML更好用的Java Annotation比XML更好用的Java Annotation
比XML更好用的Java Annotation
 
Android best practices
Android best practicesAndroid best practices
Android best practices
 
Codemotion appengine
Codemotion appengineCodemotion appengine
Codemotion appengine
 
Laurens Van Den Oever Xopus Presentation
Laurens Van Den Oever Xopus PresentationLaurens Van Den Oever Xopus Presentation
Laurens Van Den Oever Xopus Presentation
 
Android Design Patterns
Android Design PatternsAndroid Design Patterns
Android Design Patterns
 
Javascript Design Patterns
Javascript Design PatternsJavascript Design Patterns
Javascript Design Patterns
 
Building Modern Apps using Android Architecture Components
Building Modern Apps using Android Architecture ComponentsBuilding Modern Apps using Android Architecture Components
Building Modern Apps using Android Architecture Components
 
Architecture components - IT Talk
Architecture components - IT TalkArchitecture components - IT Talk
Architecture components - IT Talk
 
Architecture Components
Architecture Components Architecture Components
Architecture Components
 
Overview of Android Infrastructure
Overview of Android InfrastructureOverview of Android Infrastructure
Overview of Android Infrastructure
 
Overview of Android Infrastructure
Overview of Android InfrastructureOverview of Android Infrastructure
Overview of Android Infrastructure
 
The Full Power of ASP.NET Web API
The Full Power of ASP.NET Web APIThe Full Power of ASP.NET Web API
The Full Power of ASP.NET Web API
 
ActiveWeb: Chicago Java User Group Presentation
ActiveWeb: Chicago Java User Group PresentationActiveWeb: Chicago Java User Group Presentation
ActiveWeb: Chicago Java User Group Presentation
 
Android dev toolbox
Android dev toolboxAndroid dev toolbox
Android dev toolbox
 
Sencha / ExtJS : Object Oriented JavaScript
Sencha / ExtJS : Object Oriented JavaScriptSencha / ExtJS : Object Oriented JavaScript
Sencha / ExtJS : Object Oriented JavaScript
 
A Rich Web Experience with jQuery, Ajax and .NET
A Rich Web Experience with jQuery, Ajax and .NETA Rich Web Experience with jQuery, Ajax and .NET
A Rich Web Experience with jQuery, Ajax and .NET
 
Ajax Fundamentals Web Applications
Ajax Fundamentals Web ApplicationsAjax Fundamentals Web Applications
Ajax Fundamentals Web Applications
 
Workshop 23: ReactJS, React & Redux testing
Workshop 23: ReactJS, React & Redux testingWorkshop 23: ReactJS, React & Redux testing
Workshop 23: ReactJS, React & Redux testing
 
A Rich Web experience with jQuery, Ajax and .NET
A Rich Web experience with jQuery, Ajax and .NETA Rich Web experience with jQuery, Ajax and .NET
A Rich Web experience with jQuery, Ajax and .NET
 

Mehr von DataArt

Digital Marketing from inside
Digital Marketing from insideDigital Marketing from inside
Digital Marketing from inside
DataArt
 
A. Sirota "Building an Automation Solution based on Appium"
A. Sirota "Building an Automation Solution based on Appium"A. Sirota "Building an Automation Solution based on Appium"
A. Sirota "Building an Automation Solution based on Appium"
DataArt
 
Эмоциональный интеллект или как не сойти с ума в условиях сложного и динамичн...
Эмоциональный интеллект или как не сойти с ума в условиях сложного и динамичн...Эмоциональный интеллект или как не сойти с ума в условиях сложного и динамичн...
Эмоциональный интеллект или как не сойти с ума в условиях сложного и динамичн...
DataArt
 

Mehr von DataArt (20)

DataArt Custom Software Engineering with a Human Approach
DataArt Custom Software Engineering with a Human ApproachDataArt Custom Software Engineering with a Human Approach
DataArt Custom Software Engineering with a Human Approach
 
DataArt Healthcare & Life Sciences
DataArt Healthcare & Life SciencesDataArt Healthcare & Life Sciences
DataArt Healthcare & Life Sciences
 
DataArt Financial Services and Capital Markets
DataArt Financial Services and Capital MarketsDataArt Financial Services and Capital Markets
DataArt Financial Services and Capital Markets
 
About DataArt HR Partners
About DataArt HR PartnersAbout DataArt HR Partners
About DataArt HR Partners
 
Event management в IT
Event management в ITEvent management в IT
Event management в IT
 
Digital Marketing from inside
Digital Marketing from insideDigital Marketing from inside
Digital Marketing from inside
 
What's new in Android, Igor Malytsky ( Google Post I|O Tour)
What's new in Android, Igor Malytsky ( Google Post I|O Tour)What's new in Android, Igor Malytsky ( Google Post I|O Tour)
What's new in Android, Igor Malytsky ( Google Post I|O Tour)
 
DevOps Workshop:Что бывает, когда DevOps приходит на проект
DevOps Workshop:Что бывает, когда DevOps приходит на проектDevOps Workshop:Что бывает, когда DevOps приходит на проект
DevOps Workshop:Что бывает, когда DevOps приходит на проект
 
IT Talk Kharkiv: «‎Soft skills в IT. Польза или вред? Максим Бастион, DataArt
IT Talk Kharkiv: «‎Soft skills в IT. Польза или вред? Максим Бастион, DataArtIT Talk Kharkiv: «‎Soft skills в IT. Польза или вред? Максим Бастион, DataArt
IT Talk Kharkiv: «‎Soft skills в IT. Польза или вред? Максим Бастион, DataArt
 
«Ноль копеек. Спастись от выгорания» — Сергей Чеботарев (Head of Design, Han...
 «Ноль копеек. Спастись от выгорания» — Сергей Чеботарев (Head of Design, Han... «Ноль копеек. Спастись от выгорания» — Сергей Чеботарев (Head of Design, Han...
«Ноль копеек. Спастись от выгорания» — Сергей Чеботарев (Head of Design, Han...
 
Communication in QA's life
Communication in QA's lifeCommunication in QA's life
Communication in QA's life
 
Нельзя просто так взять и договориться, или как мы работали со сложными людьми
Нельзя просто так взять и договориться, или как мы работали со сложными людьмиНельзя просто так взять и договориться, или как мы работали со сложными людьми
Нельзя просто так взять и договориться, или как мы работали со сложными людьми
 
Знакомьтесь, DevOps
Знакомьтесь, DevOpsЗнакомьтесь, DevOps
Знакомьтесь, DevOps
 
DevOps in real life
DevOps in real lifeDevOps in real life
DevOps in real life
 
Codeless: автоматизация тестирования
Codeless: автоматизация тестированияCodeless: автоматизация тестирования
Codeless: автоматизация тестирования
 
Selenoid
SelenoidSelenoid
Selenoid
 
Selenide
SelenideSelenide
Selenide
 
A. Sirota "Building an Automation Solution based on Appium"
A. Sirota "Building an Automation Solution based on Appium"A. Sirota "Building an Automation Solution based on Appium"
A. Sirota "Building an Automation Solution based on Appium"
 
Эмоциональный интеллект или как не сойти с ума в условиях сложного и динамичн...
Эмоциональный интеллект или как не сойти с ума в условиях сложного и динамичн...Эмоциональный интеллект или как не сойти с ума в условиях сложного и динамичн...
Эмоциональный интеллект или как не сойти с ума в условиях сложного и динамичн...
 
IT talk: Как я перестал бояться и полюбил TestNG
IT talk: Как я перестал бояться и полюбил TestNGIT talk: Как я перестал бояться и полюбил TestNG
IT talk: Как я перестал бояться и полюбил TestNG
 

Kürzlich hochgeladen

Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Victor Rentea
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Safe Software
 
Architecting Cloud Native Applications
Architecting Cloud Native ApplicationsArchitecting Cloud Native Applications
Architecting Cloud Native Applications
WSO2
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
?#DUbAI#??##{{(☎️+971_581248768%)**%*]'#abortion pills for sale in dubai@
 

Kürzlich hochgeladen (20)

ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
 
Ransomware_Q4_2023. The report. [EN].pdf
Ransomware_Q4_2023. The report. [EN].pdfRansomware_Q4_2023. The report. [EN].pdf
Ransomware_Q4_2023. The report. [EN].pdf
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
 
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
 
Manulife - Insurer Transformation Award 2024
Manulife - Insurer Transformation Award 2024Manulife - Insurer Transformation Award 2024
Manulife - Insurer Transformation Award 2024
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 
Architecting Cloud Native Applications
Architecting Cloud Native ApplicationsArchitecting Cloud Native Applications
Architecting Cloud Native Applications
 
Cyberprint. Dark Pink Apt Group [EN].pdf
Cyberprint. Dark Pink Apt Group [EN].pdfCyberprint. Dark Pink Apt Group [EN].pdf
Cyberprint. Dark Pink Apt Group [EN].pdf
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024
 
DBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor PresentationDBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor Presentation
 
DEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
DEV meet-up UiPath Document Understanding May 7 2024 AmsterdamDEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
DEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
 
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ..."I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of Terraform
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
 
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
 

Тарас Олексин - Sculpt! Your! Tests!

  • 2.  4+ years of test automation experience (in company, freelance)  Enjoys building simple and elegant solutions  Has beautiful eyes
  • 3. READABILITY more than 70% of a developers time is spend reading and understanding code* *https://blogs.msdn.microsoft.com/peterhal/2006/01/04/what-do-programmers-really-do-anyway-aka-part-2-of-the-yardstick-saga/
  • 4.  Tuning your language extension libraries new features  Readable web UI test stack  Sculpting! Your! Tests! WE’LL TALK:
  • 5. LOMBOK both beautiful island in Indonesia and awesome Java extension library https://projectlombok.org/
  • 6. TYPE INFERENCE automatic deduction of the data type of an expression
  • 7. LOCAL VARIABLE TYPE INFERENCE boolean isRemoteEnabled = true; final String browser = getProperty("browser", "FIREFOX"); final ArrayList<ProductType> productTypeList = new ArrayList<>(); var isRemoteEnabled = true; val browser = getProperty("browser", "FIREFOX"); val productTypeList = new ArrayList<ProductType>();
  • 8. TYPE INFERENCE val – final local variable var – non-final local variable works on: local variables loop scope variables https://habrahabr.ru/post/280075/ http://openjdk.java.net/jeps/286
  • 9. POJO public AutomationEngineer(String name, boolean likesToBuildFrameworks, boolean hatesBDD) { this.name = name; this.likesToBuildFrameworks = likesToBuildFrameworks; this.hatesBDD = hatesBDD; } public class AutomationEngineer { … private final String name; private final boolean likesToBuildFrameworks; private final boolean hatesBDD;
  • 10. public String getName() {return name;} public boolean hatesBDD() { return hatesBDD; } public boolean likesToBuildFrameworks() { … } @Override public boolean equals(Object o) { … } @Override public int hashCode() { … } @Override public String toString() { … } } POJO
  • 11. LOMBOK public class AutomationEngineer { private final String name; private final boolean likesToBuildFrameworks; private final boolean hatesBDD; } @Data
  • 12. public enum State { ALABAMA("AL", 1), ALASKA("AK", 2), ARIZONA("AZ", 3), CALIFORNIA("CA", 4); private final String shortName; private final int stateIndex; } LOMBOK State(String shortName, int stateIndex) { this.shortName = shortName; this.stateIndex = stateIndex; } public String getShortName() { return shortName; } public int getStateIndex() { return stateIndex; } } @Getter @RequiredArgsConstructor
  • 13. EXTENSION METHOD a method added to an object after the original object was compiled
  • 14. EXTENSION METHOD new ChromeDriver() .getClickableElement(By.id("some_id")) .click(); new ChromeDriver() .findElement(By.id("some_id")) .click();
  • 15. EXTENSION METHOD public class WebElementExtension { public static WebElement getClickableElement(WebDriver driver, By by){ return new WebDriverWait(driver, 30) .until(ExpectedConditions.elementToBeClickable(by)); } } @ExtensionMethod(WebElementExtension.class) public class ExtensionMethodExample { @Test void testDriverExtension(){ new ChromeDriver() .getClickableElement(By.id("some_id")) .click(); } }
  • 17. VAVR (EX JAVASLANG) functional library for Java 8+ to reduce the amount of code and to increase the robustness http://blog.vavr.io/
  • 18. PATTERN MATCHING act of checking a given sequence for the presence of the constituents of some pattern http://cr.openjdk.java.net/~briangoetz/amber/pattern-match.html
  • 19. PLAIN JAVA public void filterUsersBy(UserType user) { WebElement userLocator; switch (user) { case ADMIN: userLocator = adminUserLocator; break; case MEMBER: userLocator = memberUserLocator; break; case VENDOR: userLocator = vendorUserLocator; break; default: userLocator = superAdminLocator; break; } select(userLocator); click(filterButton); }
  • 20. public void filterUsersBy(UserType user) { val userLocator = Match(user).of( Case($(ADMIN), adminUserLocator), Case($(MEMBER), memberUserLocator), Case($(VENDOR), vendorUserLocator), Case($(), superAdminLocator) ); select(userLocator); click(filterButton); } VAVR
  • 21. public void doActionFor(UserType user) { Match(user).of( Case(isIn(ADMIN, SUPER_ADMIN), obj -> run(this::selectAdminUser)), Case($(MEMBER), obj -> run(this::selectMemberUser)), Case($(), obj -> {throw new SomeException("Invalid user: “ + obj);}) ); } VAVR
  • 22. OWNER library for getting rid of the boilerplate code in properties based configuration http://owner.aeonbits.org/
  • 24. public interface BrowserSetting extends Config { String browserName(); String version(); Platform platform(); boolean isRemote(); boolean javascriptEnabled(); boolean acceptSslCerts(); } OWNER BrowserSetting.properties: browserName=firefox version=57 platform=WINDOWS isRemote=true javascriptEnabled=true acceptSslCerts=false
  • 27. public List<Product> getProductsFor(ProductCategory category) { return filteredProducts; } JAVA List<WebElement> products = getVisibleElementsFor(productsLocator); List<Product> filteredProducts = new ArrayList<>(); for (WebElement productElement : products) { String productName = productElement.getText(); String productCategory = getCategoryFrom(productName); } if (productCategory.equals(category)) { Product product = new Product(productName); filteredProducts.add(product); }
  • 28. public List<Product> getProductsFor(ProductCategory category) { return getVisibleElementsFor(productsLocator) .stream() .map(WebElement::getText) .filter(productName -> getCategoryFrom(productName).equals(category)) .map(Product::new) .collect(toList()); } JAVA 8
  • 29.
  • 30. Gradle TestNG Selenide Allure AssertJ DSL layer Selenium Grid/Selenoid TO GO STACK API
  • 31. SELENIDE WebDriverManager ThreadLocal static instance SelenideElement built-in smart waits file uploads … maintain browser drivers manage WebDriver instance UI mapping wait strategies assertions …
  • 32. ASSERTJ void verifyAddingApplicant() { … assertTrue("John Smith".equals(applicant.getName()), "Failed to update applicant name"); … assertTrue(applicantsTable.getRecordsCount() == 1, “Applicants table has more than 1 record"); } void verifyAddingApplicant() { … assertThat(applicant).hasName(“John Smith“); … assertThat(applicantsTable).hasRecords(1); }
  • 33. CUSTOM ASSERT public class ApplicantAssert extends AbstractAssert<ApplicantAssert, ApplicantInfo> { public ApplicantAssert(ApplicantInfo actual) { super(actual, ApplicantAssert.class); } public static ApplicantAssert assertThat(ApplicantInfo actual) { return new ApplicantAssert(actual); } public ApplicantAssert hasName(String name) { ... } }
  • 34. SCULPTING! YOUR! TESTS! extending language with libraries using new language features using ready solutions building concise DSL
  • 35. void testAddingApplicant() { final ApplicantInfo applicant = getApplicantInfo(); final EducationInfo education = getEducationInfo(); applicantsPage .startAddingApplicant() .fillAllFieldsWith(applicant) .startAddingInfo(ApplicantInfoType.EDUCATION) .fillAllFieldsWith(education) .saveApplicant(); assertTrue(applicantsPage.getApplicantAddedMessage().isDisplayed(), "Failed to add new applicant"); } 1 2 3
  • 36. final ApplicantInfo applicant = getApplicantInfo(); final EducationInfo education = getEducationInfo(); assertThat(applicantsPage).applicantAdded(); applicantsPage .startAddingApplicant() .fillAllFieldsWith(applicant) .startAddingInfo(ApplicantInfoType.EDUCATION) .fillAllFieldsWith(education) .saveApplicant(); assertTrue(applicantsPage .getApplicantAddedMessage().isDisplayed(), "Failed to add new applicant"); val applicant = getApplicantInfo(); val education = getEducationInfo(); applicantsPage .add(applicant) .addInfo(education) .saveApplicant();
  • 37. void testAddingApplіcant() { val applicant = getApplicantInfo(); val education = getEducationInfo(); applicantsPage .add(applicant) .addInfo(education) .saveApplicant(); assertThat(applicantsPage).applicantAdded(); }
  • 38. void testAddingApplicant() { final ApplicantInfo applicant = getApplicantInfo(); final EducationInfo education = getEducationInfo(); applicantsPage .startAddingApplicant() .fillAllFieldsWith(applicant) .startAddingInfo(ApplicantInfoType.EDUCATION) .fillAllFieldsWith(education) .saveApplicant(); assertTrue(applicantsPage.getApplicantAddedMessage().isDisplayed(), "Failed to add new applicant"); }
  • 39. ADVANTAGES ? decreased code base increased code readability time saved for adding actual value …
  • 40. DOWNSIDES ? learning curve complexity increases external risks …
  • 42. HOW TO PRONOUNCE ? [SUITE] pronounced like Jason[JSON] [LINUX] pronounced sweet pronounced like the name [leenooks]