Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

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

Slide 3

Slide 3 text

Base Test Class

Slide 4

Slide 4 text

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.

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

Examples without the usage of Base Test class β—‹ FirstPageCheckTest with the usage of Base Test class β—‹ BaseTestWeb β—‹ FirstPageCheckTest

Slide 8

Slide 8 text

Builder and Fluent Interface

Slide 9

Slide 9 text

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; } }

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

Examples builder implementation β—‹ Product β—‹ ProductBuilder β—‹ ProductBuilderTest fluent interface β—‹ AmazonPage β—‹ Department β—‹ FluentInterfaceTest

Slide 13

Slide 13 text

Factory

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

Examples browser factory β—‹ BrowserFactory β—‹ FactoryTest

Slide 17

Slide 17 text

Data Generation

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

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();

Slide 20

Slide 20 text

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() {} }

Slide 21

Slide 21 text

Examples data factory β—‹ CreditCardDataFactory β—‹ DataFactoryTest

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

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.

Slide 24

Slide 24 text

Examples Changeless data β—‹ AssertionData β—‹ BrowserData β—‹ GeneralData

Slide 25

Slide 25 text

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")) ); }

Slide 26

Slide 26 text

Examples data driven β—‹ CreditCardDataDriven β—‹ DataDrivenTest

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

Configuration Management

Slide 29

Slide 29 text

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.

Slide 30

Slide 30 text

Examples configuration management β—‹ Configuration β—‹ ConfigurationManager β—‹ config.properties β—‹ WebConfigTest

Slide 31

Slide 31 text

Logs and Reports

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

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.

Slide 34

Slide 34 text

Examples logs β—‹ log4j2.properties β—‹ CreditCardDataFactory β—‹ 3-design-patterns-arch-decision.log file generated in your user folder

Slide 35

Slide 35 text

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…

Slide 36

Slide 36 text

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

Slide 37

Slide 37 text

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