$30 off During Our Annual Pro Sale. View Details »

3 Design Patterns and Architecture Decisions you must use in your project

3 Design Patterns and Architecture Decisions you must use in your project

This presentation shows the following:

- Base Test Class: not only the basics but why you can be benefited from multiples bases tests classes

- Fluent builder: we can use it to create fluent interfaces, data objects and bring fluency in the usage of the methods

- Factory: does not matter if you are going to create a browser instance or open a new mobile device… it must be used in all targeting environments to test

- Data Generation: we can apply different strategies like the Test Data Factory, Data-Driven, or even consuming data from dynamic data sources

- Configuration management: because we don't have much time to change the code all the time we can use a proper configuration approach to avoid changes in the codebase

-Logs and reports: logs will help us to better understand what happened in that failed test, where reports will generate information that everyone can understand

Elias Nogueira

August 11, 2021
Tweet

More Decks by Elias Nogueira

Other Decks in Technology

Transcript

  1. 3 Design Patterns and
    Architecture Decisions you
    must use in your project
    Elias Nogueira

    View Slide

  2. Elias Nogueira
    I help professional software engineers
    (backend, frontend, qa) to develop their
    quality mindset and deliver bug-free software
    so they become top-level engineers and get
    hired for the best positions in the market.
    🏢
    Backbase
    👨💻‍‍
    Principal Software Engineer
    📍
    Utrecht, the Netherlands
    🌐
    eliasnogueira.com
    🐦
    @eliasnogueira
    bit.ly/eliasnogueira

    View Slide

  3. Base Test Class

    View Slide

  4. Base Test Class
    It is a simple approach to set up a shared initialization and
    cleanup in your tests. We commonly categorize it as a Testing
    pattern.
    The problem we are trying to solve here is the reuse of common
    behaviors across test classes avoiding coding duplication and
    centralizing these actions at one point.
    The application of a Base test class in OO programming
    languages is applied using inheritance.

    View Slide

  5. Base Test Class
    Without this approach, we have code duplicated related to:
    ○ pre-condition
    ○ post-condition
    ○ any shared method
    TEST 1 TEST 2 TEST 3
    pre-condition
    post-condition
    pre-condition
    post-condition
    pre-condition
    post-condition

    View Slide

  6. Base Test Class
    With this approach, we have:
    ○ the smart use of inheritance
    ○ an easy way to add more test
    ○ flexible creation of test suites
    BASE TEST
    CLASS
    TEST 1
    TEST 2
    TEST 3
    browser initialization/close
    open/close database, logs
    connect/disconnect servers
    login/logout app

    View Slide

  7. Examples
    without the usage of Base Test class
    ○ FirstPageCheckTest
    with the usage of Base Test class
    ○ BaseTestWeb
    ○ FirstPageCheckTest

    View Slide

  8. Builder and Fluent Interface

    View Slide

  9. Builder
    This pattern tries to manage the construction process of an
    object using its constructor in fluent methods.
    Regular class example
    public class Product {
    private final String name;
    private final String description;
    private final BigDecimal price;
    public Product(String name, String description, BigDecimal price) {
    this.name = name;
    this.description = description;
    this.price = price;
    }
    }

    View Slide

  10. Builder
    public class ProductBuilder {
    private String name;
    private String description;
    private BigDecimal price;
    public ProductBuilder name(String name) {
    this.name = name;
    return this;
    }
    public ProductBuilder description(String description) {
    this.description = description;
    return this;
    }
    public ProductBuilder price(BigDecimal price) {
    this.price = price;
    return this;
    }
    public Product build() {
    return new Product(name, description, price);
    }
    }
    Builder construction
    ● All methods return the class (this)
    ● The build() method call the constructor

    View Slide

  11. Fluent Interface
    This pattern tries to provide a readable fluent API over a
    specific domain. The domain can include more than one class.
    public class AmazonPage {
    public AmazonPage selectDepartment(Departament departament) {
    // some magic here
    return this;
    }
    public AmazonPage search(String term) {
    // some magic here
    return this;
    }
    }
    class FluentInterfaceTest {
    @Test
    void searchInAllDepartaments() {
    AmazonPage amazonPage = new AmazonPage();
    amazonPage.search("Kindle Fire");
    }
    @Test
    void searchOnComputers() {
    AmazonPage amazonPage = new AmazonPage();
    amazonPage.selectDepartment(Department.BOOKS)
    .search("Effective Java");
    }
    }
    Fluent interface Usage

    View Slide

  12. Examples
    builder implementation
    ○ Product
    ○ ProductBuilder
    ○ ProductBuilderTest
    fluent interface
    ○ AmazonPage
    ○ Department
    ○ FluentInterfaceTest

    View Slide

  13. Factory

    View Slide

  14. Factory
    This creational pattern enables the creation of objects without
    exposing the internal logic.
    A good test example is the creation of different browser instances.
    BROWSER
    FACTORY
    FIREFOX SAFARI
    EDGE
    CHROME

    View Slide

  15. Factory
    The basic implementation is done by having specific classes
    that will create different objects, while the main class is
    responsible to understand the object type to create it.
    More information at
    http://www.eliasnogueira.com/how-to-use-the-factory-design-pattern-to-create-browser-instances-the-simple-approach

    View Slide

  16. Examples
    browser factory
    ○ BrowserFactory
    ○ FactoryTest

    View Slide

  17. Data Generation

    View Slide

  18. Data Generation
    There are many ways to generate data…
    The most common are:
    STATIC/DYNAMIC
    GENERATION
    FAKES

    View Slide

  19. Fake Generation
    Creates an approach to generate non-sensitive data for your
    test without manually changing the test data in each execution.
    There’re a lot of tools to create this type of data.
    Example with Java-Faker
    Faker faker = new Faker(new Locale("pt-BR"));
    faker.name().fullName();
    faker.address().fullAddress();
    faker.internet().emailAddress();
    faker.business().creditCardNumber();
    faker.date().birthday();

    View Slide

  20. Fake Generation + Data Factory
    We can use a Fake Generation in a centralized data class that
    can create data in any condition.
    public class CreditCardDataFactory {
    public CreditCard validCreditCard() {}
    public CreditCard invalidCreditCardNumber() {}
    public CreditCard invalidMonth() {}
    public CreditCard invalidYear() {}
    public CreditCard invalidCcv() {}
    }

    View Slide

  21. Examples
    data factory
    ○ CreditCardDataFactory
    ○ DataFactoryTest

    View Slide

  22. Static Generation
    When the data cause different behaviors in your application.
    A Static approach can be achieved by implementing any data
    approach like:
    ○ Class
    ○ CSV | JSON | TXT | YML
    ○ Database
    ○ Mock

    View Slide

  23. Changeless data
    It’s a set of common data used across the project consisting of
    a final class containing constants.
    The changeless data (constants) will be used in different classes and
    the advantage is the single point of change.
    We can have multiple classes shaping the different data requirements.

    View Slide

  24. Examples
    Changeless data
    ○ AssertionData
    ○ BrowserData
    ○ GeneralData

    View Slide

  25. Data Driven
    It is one of the Static data generation types.
    It consists of using different data in the same test, where the
    data changes, not the test.
    Different test libraries have this approach available.
    Most of them consist of the data hard-coded in a test class.
    More info about JUnit 5 data driven methods at:
    https://junit.org/junit5/docs/current/user-guide/#writing-tests-parameterized-tests
    @Override
    public Stream extends Arguments> provideArguments(ExtensionContext extensionContext) {
    return Stream.of(
    arguments("Micro SD Card 16Gb", new BigDecimal("6.09")),
    arguments("JBL GO 2", new BigDecimal("22.37")),
    arguments("iPad Air Case", new BigDecimal("14.99"))
    );
    }

    View Slide

  26. Examples
    data driven
    ○ CreditCardDataDriven
    ○ DataDrivenTest

    View Slide

  27. Dynamic Generation
    The Dynamic approach can be implemented according to
    your context.
    Used to remove the maintenance of test data. Example:
    ○ Queries in a database
    ○ Consume data from an API

    View Slide

  28. Configuration Management

    View Slide

  29. Configuration Management
    It provides a way to set different values for a running application
    without the necessity of re-compile or re-run it.
    Normally, this approach accepts dynamic values injection through
    environment variables or by modifying a configuration file.

    View Slide

  30. Examples
    configuration management
    ○ Configuration
    ○ ConfigurationManager
    ○ config.properties
    ○ WebConfigTest

    View Slide

  31. Logs and Reports

    View Slide

  32. Logs and Reports
    We can generate logs and reports in different ways, but it’s
    important to have both in your test project whatever the tools
    you will choose for this.
    TEST REPORT
    EXCEPTIONS AND
    BASIC LOGS

    View Slide

  33. Exceptions and basic logs
    By using any log strategy, saving a log file, we can understand
    the common errors that occurred during the test execution.
    These errors can be of:
    ○ assertion errors
    ○ timeout exceptions
    ○ locator exception
    ○ an exception on your architecture
    You can also log basic info to know some action you are doing
    in the code.

    View Slide

  34. Examples
    logs
    ○ log4j2.properties
    ○ CreditCardDataFactory
    ○ 3-design-patterns-arch-decision.log file generated in your user folder

    View Slide

  35. Test Report
    Do not matter if you will generate the test report in any style
    (below): the most important thing is to have one to satisfy your
    requirements.
    We can have it reported as:
    ○ Gherkin style (readable by humans)
    ○ xUnit style (readable by CI/CD tools)
    ○ HTML (readable by humans)
    ○ any other style like XML, JSON, etc…

    View Slide

  36. Examples
    reports
    ○ allure.properties
    ○ Allure configuration placed on pom.xml
    ○ auto-generated xUnit XML reports at target/surefire-reports

    View Slide

  37. Thanks!
    SCAN ME
    You can follow me on Twitter
    @eliasnogueira and find the
    practical examples of this
    presentation. Be sure to simulate
    the examples in the code!
    github.com/eliasnogueira/3-design-patters-arch-decisions

    View Slide