How to Build Your Own Test Automation Framework? Dmitry Buzdin TAPOST 18 October 11th/12th
Working as a consultant • DevOps (Jenkins, Docker, Cloud etc) • Test Automation (TDD, BDD, ATDD, ?DD) • Software Architecture (aka Microservices) • Java/Web Development @buzdin About Trainer
Agenda • What is expected from a test framework? • What makes a test framework? • How to make one? • What should be considered?
Test Framework Expectations
Lets Create a Test Automation Framework!
Requirements • Minimal cost of ownership • No vendor lock-in • Large user base • Integration with existing tools • Longevity • Transparency
Assembling open source test framework based on Java
What Makes a Test Framework?
Framework vs Library • Frameworks have key distinguishing features that separate them from normal libraries: • inversion of control: In a framework, unlike in libraries or in standard user applications, the overall program's flow of control is not dictated by the caller, but by the framework. • extensibility: A user can extend the framework - usually by selective overriding; or programmers can add specialized user code to provide specific functionality. • non-modifiable framework code: The framework code, in general, is not supposed to be modified, while accepting user- implemented extensions. In other words, users can extend the framework, but should not modify its code. https://en.wikipedia.org/wiki/Software_framework
Where would you find 
 the building blocks?
Download a Cucumber
VS How to know if the component is good or bad?
We need some architecture guidelines
ISTQB Generic Test Automation Architecture
Not sure if this is related to the real world automated testing?
Test Definition Layer Test Procedures Test Cases Test Conditions Test Data Test Library
Test Library • Collection of reusable elements to compose test cases • Directly related to business logic of SUT • The most valuable asset, which should outlive framework changes
Test Step @Step public void login(String username, String password) { // performs login } @Step public void navigateToPage(String page) { // navigates browser to specified page } Test Library == Test Steps
Test Step Benefits • Using minimal features of the actual framework • Independent from each other • Parametrised with inputs Test Framework should support technology agnostic test steps
Test Conditions • Test conditions are methods to check expectations • Important selection factors: • Possibility to write/find custom assertions • Clarity of failure messages • Additional assertion strategies Test Conditions == Assertions
Fluent Assertions http://joel-costigliola.github.io/assertj/ Readable assertions with auto-completion support
Power Assertions available in Groovy
Soft Assertions @org.junit.Rule public final JUnitSoftAssertions softly; @Step public void ensureAllFieldsAreDisabledForUser() { … softly.assertThat(user.getText()).isEqualTo("user"); softly.assertThat(nameInput.isEnabled()).isFalse(); softly.assertThat(surnameInput.isEnabled()).isFalse(); softly.assertThat(submitButton.isEnabled()).isFalse(); softly.assertThat(logoutButton.isEnabled()).isTrue(); … } All assertion failures are recorded until end of the test
Assertion Groups assertAll("person", () -> assertEquals("John", person.getFirstName()), () -> assertEquals("Doe", person.getLastName()) ); All assertions in a group are evaluated at the same time. You will see all errors in output together. http://junit.org/junit5/
Test Data • Test Data is used to define test inputs for abstract test cases • Test Data can come from different sources and formats
Data Tables Spock Framework
JUnit 5 Data-Driven @ParameterizedTest @CsvFileSource(resources = "/data/users.csv") public void testWithParameters( String user, String password, Integer id) { logger.info("{}:{}:{}", user, password, id); }
Test Cases “A set of input values, execution preconditions, expected results and execution postconditions, developed for a particular objective or test condition, such as to exercise a particular program path or to verify compliance with a specific requirement.” http://glossary.istqb.org/search/test%20case
Test Case in Manual Testing No Test Step Expectation Data 1 User logs in navigated to home page username=“joe” 2 User selects item navigated to item page item=“123” 3 User clicks “Add to Cart” Shopping cart updated 4 User clicks “Go To Cart” navigated to shopping cart 5 User clicks “Checkout” Checkout screen opens
Automated Testing Where are all the test steps?
Proper Test Case @Test public void checkoutTest() { login(“joe”, “password”); assertOnPage(“/home”); viewItem(123); assertOnPage(“/item.123”); addToCart(); assertCartItems(1); goToCart(); … } Test Case contains: • test steps • assertions • test data
Abstract vs Concrete • Abstract (high-level) test cases • Concrete (low-level) test cases = Data-Driven • Relation between them should be kept Test Framework should distinguish between those @TestTemplate public void abstractTest(Data data) { }
Test Procedurs Defines how to select and run a set of test cases? Test Procedures == Test Suites
Testing Assets Test Plans / Test Suites Test Cases Test Steps Test Libraries Test Data Assertions
There is one more component!
Test Language •You could write test cases in: •Gherkin •Java/Groovy •Excel •HTML •Markdown All of that could coexist in a single framework!
Gherkin Language Cross-platform specification Cucumber JVM works both with JUnit and TestNG Test Step Test Conditions Test Step Test Case
Plain Language @Test public void ensureAllFieldsAreDisabledForUser() { goToPage(“/login“); login(“janedoe”, “password”); assertPage(“/home”); logout(); } Same test in Java
Multi-Language Framework Gherkin Test Cases Test Steps Test Adapters JUnit Test Cases Cucumber Step Defs Reusing the same test steps, data and assertions
Test Execution Layer Test Execution Test Logging Test Reporting
Test Execution • API for Test Case creation • Extension model • Engine to run the tests • External API to IDE, Build tools and GUI
JUnit 5 Architecture Test Runner Test Engine Test Language
Test Engine Responsibilities • Provides API/Language for Test Definition • Discovers test cases • Knows how to run tests • Provide engine-specific extension points
Test Runner Responsibilities • Integrates with IDE, Build and others tools • Integrates with Test Engines • Runs tests according to test plan • Starts multiple engines if needed • Provides extension points
Test Logging • Recording test execution event for further analysis • Test logs are attached to test reports • Vital to decrease investigation time of failures
System.out.println( “HTTP Result for ” + req.getUrl() + “ is ” + resp.getStatus() ); This isn’t a good test logging strategy!
Logger Frameworks • Possibility to change level of detail (runtime) • Log message tagging • Configurable log message format private static final Logger logger = LoggerFactory.getLogger(“NAME”); logger.info(“Hello, logger!”);
Log Management Tools
Test Reporting • Has to make sense to your Product Owner • Technical drill-down should be available • Aid in decision making process
Typical Test Report This is a very poor test report
Open Questions • What feature failed? • Was this test failing recently? • Is this the only test with such exception? • Are there any screenshots? • Which test inputs were used? • Which environment?
Allure Framework 2.0
Test Case Run Details
Test Metadata @Epic("JIRA-123") @Story("JIRA-456") @Feature(“Login") @Description("hello") @Owner("dmitry.buzdin") @Severity(SeverityLevel.NORMAL) @Test public void allureTest() {…}
More Features • Test steps are auto discovered • Test data is captured • All attachments are placed to according places • Historical analysis: flakiness, screenshot diffs
Test Configuration • Loading environment configurations • Configuration profiles • Different configuration sources (json, yaml, xml, external system) • Configuring SUT before test run
OWNER Library http://owner.aeonbits.org/
Dependency Injection • Necessary because of all building blocks • Keeping intermediate results • Keeping virtual user sessions * same name for inversion of control
Dependency Scopes • Test run scope • Test suite scope • Test case scope • User session scope
Test Adaptation Layer GUI API Services Protocols Databases Simulators Emulators
Test Adaptation Layer • Means to interact with SUT • GUI: Web, Mobile, Desktop, Image Recognition • Protocols: HTTP, AMQP, SSH • Database connectors
Test Adapters • Adapters should be configurable • Adapters should be independent from other test framework components • Adapters should be easy to use and replace
Rest Assured http://rest-assured.io/ when(). get("/lotto/{id}", 5). then(). statusCode(200). body("lotto.lottoId", equalTo(5), "lotto.winners.winnerId", containsOnly(23, 54)); Adapter DSL + Inversion of Control + Assertions Easy to use, but hard to integrate with other tools
Sometimes, 
 simple HttpClient
 is a better choice…
Building a Test Framework
Pieces of the Puzzle Configuration Test Reporting Test Engine Assertions Logging Dependency Injection Test Language Test Adapters Test Runner Test Data
Sample Java Stack Component Technology Test Engine JUnit 5 Test Reporting Allure 2 Assertions AssertJ Configurations OWNER Test Language Cucumber-JVM Logging Logback Test Adapters Rest-assured, Selenide etc. Dependency Injection Guice Data-driven JUnit 5 + Extensions
How it all fits together? • Test Automator value is in knowing all pieces of puzzle and integrating those • Skills and experience required! • Plugins, plugins, plugins…
Tool Evaluation Checklist • Documentation quality • Number of extensions points • Number of plugins • StackOverflow responsiveness • Project statistics • Open standards
Git Hub Stats
Open Standards / APIs • Gherkin language • WebDriver https://www.w3.org/TR/webdriver/ • JUnit 5 Platform • Allure Reporting Result Format
Summary
You have to pick and choose components in order to build your framework
Test Automation time is now!
October 26th Allure Meetup in Riga
How to Build Your Own Test Automation Framework?

How to Build Your Own Test Automation Framework?