Slide 1

Slide 1 text

MANAGING TEST DATA @eliasnogueira

Slide 2

Slide 2 text

ELIAS NOGUEIRA Senior Principal Software Engineer Brazil Oracle Ace Java Magazine NL Editor Java Champion

Slide 3

Slide 3 text

THE PROBLEM WE WANT TO SOLVE

Slide 4

Slide 4 text

hard troubleshooting data without meaning is hard to understand [INFO ] 2023-03-05 18:03:54.081 [main] Person - model1 - Person[ name=etSfgOGRQA, surname=USwRiZSZnKdYAlYBNYJVcDFRgmSLfO, [email protected], age=1, address=XmcWoqivEzSoUwEksGNjlzrjUmWKKCIDOTsDnPAlHPQMJaWYzt] [INFO ] 2023-03-05 18:03:54.090 [main] Person - model1 - Person[ name=rtxhUtqzhV, surname=yruPCovuOMXrXUKqZnkxgrDIsdUWMY, [email protected], age=60, address=tFlnvWupyHnnHkAzuHAFzmRbrFUjwViqHSUEDjqCWfQdjKhBFM]

Slide 5

Slide 5 text

hard troubleshooting data without meaning is hard to understand [INFO ] 2023-03-05 18:03:54.081 [main] Person - model1 - Person[ name=etSfgOGRQA, surname=USwRiZSZnKdYAlYBNYJVcDFRgmSLfO, [email protected], age=1, address=XmcWoqivEzSoUwEksGNjlzrjUmWKKCIDOTsDnPAlHPQMJaWYzt]

Slide 6

Slide 6 text

not prioritized data requirements data must match any rule or restriction [INFO ] 2023-03-05 18:03:54.081 [main] Person - model1 - Person[ name=etSfgOGRQA, surname=USwRiZSZnKdYAlYBNYJVcDFRgmSLfO, [email protected], age=1, address=XmcWoqivEzSoUwEksGNjlzrjUmWKKCIDOTsDnPAlHPQMJaWYzt] probably will make a test fail

Slide 7

Slide 7 text

no patterns for data generation we must avoid code duplication private static Person personToCreate() { Person person = new Person( "Test user", "Surname", "[email protected]", 18, "User address, 50 – Brühl" ); return person; } multiple methods to generate the same data can (wrongly) exist

Slide 8

Slide 8 text

hard troubleshooting not prioritized data requirements no patterns for data generation - possibly fixed/data repetition

Slide 9

Slide 9 text

HOW TO SOLVE THE PROBLEM?

Slide 10

Slide 10 text

define a way to generate data use a specialized tool understand the data requirements know the testing library support for data 1⃣ 2⃣ 3⃣ 4⃣

Slide 11

Slide 11 text

DEFINE A WAY TO GENERATE DATA

Slide 12

Slide 12 text

There are some approaches to generating data - Combining Object Mother and Fluent Builder for the Ultimate Test Data Factory - Test Data Builders and Object Mother: another look - Writing Clean Tests – New Considered Harmful - Test Data Builders: an alternative to the Object Mother pattern define a way to generate data

Slide 13

Slide 13 text

common approaches builder pattern, in the Model objects factory pattern to generate the data tool for dynamic data generation test data factory

Slide 14

Slide 14 text

model object @Data @Builder @EqualsAndHashCode public class Simulation { @JsonIgnore private Long id; private String name; private String cpf; private String email; private BigDecimal amount; private Integer installments; private Boolean insurance; }

Slide 15

Slide 15 text

builder pattern var simulation = Simulation.builder() .cpf("94827495037") .name("John Doe") .email("[email protected]") .amount(new BigDecimal("1000")) .installments(5) .insurance(true) .build();

Slide 16

Slide 16 text

factory pattern public final class SimulationDataFactory { public static Simulation createSimulation() { return Simulation.builder().cpf("94827495037") .name("John Doe").email("[email protected]") .amount(new BigDecimal("1000")).installments(5) .insurance(true).build(); } }

Slide 17

Slide 17 text

Talk is cheap. Show me the code. Linus Torvalds

Slide 18

Slide 18 text

USE A SPECIALIZED TOOL

Slide 19

Slide 19 text

https://www.slideshare.net/JaapCoomans/fairies-fakers-and-factories-boost-your-tests-with-better-test-data

Slide 20

Slide 20 text

use a specialized tool Tool What it does Comment Easy Random Generate random data based on Java beans For a long time not updated (3 years) Uses JavaFaker for specialized data jFairy Generate data based on different aspects Uses Apache Commons library, IBAJ4J, and custom YAML files Instancio Creates and populates objects Uses a custom solution for data generation DataFaker Generate data based on YAML and random code Fork from JavaFaker with a more active community

Slide 21

Slide 21 text

datafaker Faker faker = new Faker(Locale.GERMAN); faker.name().fullName(); // Freiherrin Amar von Lienshöft faker.finance().iban("DE"); // DE37941528189220696520 faker.internet().emailAddress(); // [email protected] faker.expression("#{date.birthday ‘yy MM dd hh:mm:ss'}"); // 78 10 08 10:04:34

Slide 22

Slide 22 text

test data factory public final class SimulationDataFactory { public static Simulation createSimulation() { return Simulation.builder() .cpf("94827495037") .name("John Doe") .email(("[email protected]") .amount(new BigDecimal("1000")) .installments(5) .insurance(true) .build(); } } Combination of builder + factory

Slide 23

Slide 23 text

test data factory public final class SimulationDataFactory { public static Simulation createSimulation() { return Simulation.builder() .cpf(faker.cpf().valid()) .name(faker.name().fullName()) .email(faker.internet().emailAddress()) .amount(new BigDecimal(faker.number().numberBetween(1000, 40000))) .installments(faker.number().numberBetween(2, 48)) .insurance(faker.bool().bool()) .build(); } } Combination of builder + factory + tool

Slide 24

Slide 24 text

Talk is cheap. Show me the code. Linus Torvalds

Slide 25

Slide 25 text

UNDERSTAND THE DATA REQUIREMENTS

Slide 26

Slide 26 text

understand the data requirements When we have data requirements to follow… @Min(value = 1000, message = "Amount must be equal or greater than $ 1.000") @Max(value = 40000, message = "Amount must be equal or less than than $ 40.000") private BigDecimal amount; @Min(value = 2, message = "Installments must be equal or greater than 2") @Max(value = 48, message = "Installments must be equal or less than 48") private Integer installments;

Slide 27

Slide 27 text

public final class SimulationDataFactory { public static Simulation createSimulation() { return Simulation.builder() .cpf(faker.cpf().valid()) .name(faker.name().fullName()) .email(faker.internet().emailAddress()) .amount(new BigDecimal(faker.number().numberBetween(1000, 40000))) .installments(faker.number().numberBetween(2, 48)) .insurance(faker.bool().bool()).build(); } } We must generate the data based on that conditions understand the data requirements

Slide 28

Slide 28 text

Talk is cheap. Show me the code. Linus Torvalds

Slide 29

Slide 29 text

KNOW THE TESTING LIBRARY SUPPORT FOR DATA

Slide 30

Slide 30 text

JUnit 5 data driven Value Source Internal Method Source External Method Source Argument Provider CSV Provider

Slide 31

Slide 31 text

Value Source JUnit 5 data driven class JUnitValueSourceTest { private static final int VALUE = 7; @DisplayName("Values are greater than or equals to") @ParameterizedTest(name = "{0} is greater than or equals to " + VALUE) @ValueSource(ints = {7, 10, 12, 40}) void valueSourceExample(int value) { assertThat(value).isGreaterThanOrEqualTo(VALUE); } }

Slide 32

Slide 32 text

Internal Method Source JUnit 5 data driven class JUnitInternalMethodSourceTest { @DisplayName("All products should be cheap") @ParameterizedTest(name = "product ''{0}'' of amount ${1} is cheap") @MethodSource("cheapProducts") void cheapProducts(String product, BigDecimal amount) { final BigDecimal maximumPrice = new BigDecimal("30.0"); assertThat(product).isNotEmpty(); assertThat(amount).isLessThanOrEqualTo(maximumPrice); } static Stream cheapProducts() { 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 33

Slide 33 text

JUnit 5 data driven class JUnitExternalMethodSourceTest { private final String CHEAP_PRODUCTS = "com.eliasnogueira.datadriven.JUnitExternalData#cheapProducts"; @ParameterizedTest(name = "product ''{0}'' of amount ${1} is cheap") @MethodSource(value = CHEAP_PRODUCTS) void cheapProducts(String product, BigDecimal amount) { // test goes here } public class JUnitExternalData { public static Stream cheapProducts() { 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")) ); } External Method Source

Slide 34

Slide 34 text

Argument Provider JUnit 5 data driven class JUnitArgumentProviderTest { private static final String MAXIMUM_PRICE = "30.0"; @DisplayName("Products should not exceed the maximum price") @ParameterizedTest(name = "product ''{0}'' of amount ${1} does not exceeds $" + MAXIMUM_PRICE) @ArgumentsSource(ProductsDataArgumentProvider.class) void cheapProducts(String product, BigDecimal amount) { assertThat(product).isNotEmpty(); assertThat(amount).isLessThanOrEqualTo(new BigDecimal(MAXIMUM_PRICE)); } } public class ProductsDataArgumentProvider implements ArgumentsProvider { @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 35

Slide 35 text

CSV Provider JUnit 5 data driven class JUnitCSVSourceTest { private static final String MAXIMUM_PRICE = "30.0"; @DisplayName("Products should not exceed the maximum price") @ParameterizedTest(name = "product ''{0}'' of amount ${1} does not exceeds $" + MAXIMUM_PRICE) @CsvFileSource(resources = "/products.csv", numLinesToSkip = 1) void productsLassThan(String product, BigDecimal amount) { assertThat(product).isNotEmpty(); assertThat(amount).isLessThanOrEqualTo(new BigDecimal(MAXIMUM_PRICE)); } } product,amount Micro SD Card 16Gb,6.09 JBL GO 2,22.37 iPad Air Case,14.99 products.csv

Slide 36

Slide 36 text

Talk is cheap. Show me the code. Linus Torvalds

Slide 37

Slide 37 text

REFERENCES

Slide 38

Slide 38 text

JUnit 5 data driven Main project https://github.com/eliasnogueira/manage-testing-data-java • Value Source • Internal Method Source • External Method Source • external method source data class • Argument Provider • argument provider data class • CSV Provider • csv file

Slide 39

Slide 39 text

Main project https://github.com/eliasnogueira/credit-api/tree/manage-data • TestData Factory • Argument provider for edge cases • Tests test data factory

Slide 40

Slide 40 text

THANK YOU! @eliasnogueira https://github.com/eliasnogueira/public-speaking