Рубрики
Без рубрики

Фабрика тестовых данных: Почему и как использовать

Этот пост относится к серии “Как создать архитектуру автоматизации бережливого тестирования для Интернета с использованием Java”. I… Помечено качеством кода, java, библиотеками, архитектурой.

Этот пост относится к серии Как создать архитектуру автоматизации бережливого тестирования для Интернета с использованием Java . Если вы не видели предыдущие посты, пожалуйста, ознакомьтесь с ними!

Какую проблему это решает?

Одной из самых больших проблем при автоматизации тестирования, независимо от уровня, который вы тестируете, является управление тестовыми данными. Я бы сказал, что им довольно легко управлять на уровне модулей и интеграции, где мы можем контролировать состояние приложения, но для функциональных тестов и тестов e2e это довольно сложно.

Было бы здорово, если бы мы могли прекратить вручную изменять данные, которые у нас есть в файле кода, или даже из внешнего источника, такого как файл CSV или JSON, верно?

Мы хотели бы решить проблемы с обслуживанием кода и сбоями тестирования из-за изменений данных и создать простой и расширяемый способ генерации тестовых данных.

Что такое Фабрика тестовых данных?

У нас нет соглашения о терминологии тестирования (да, я знаю, что это отстой), и у нас нет определения подхода Фабрики тестовых данных, так что вот мое определение.

Во время некоторых исследований * (прочтите это как “Я использовал Google”) Я нашел интересные посты, связанные с той же концепцией: шаблон ObjectMother

исследование:

Пример

Подумайте, что у вас есть заявка, которую вы должны заполнить в форме, где получить кредит, где есть эти два требования:

  • ненулевое имя
  • действительный e- почта
  • сумма должна быть больше 1000 долларов США и меньше 40 000 долларов США
  • взносы должны быть больше 2 и меньше 10

Если вы уже знаете некоторые методы тестирования, вы можете увидеть, как вы применяете Анализ граничных значений (BVA) метод тестирования для ввода суммы и платежей.

Мы должны найти способ протестировать все эти возможные сценарии, заполнив форму, конечно, некоторыми данными:

  • вся достоверная информация
  • имя как нулевое
  • неверный адрес электронной почты
  • сумма менее 1000 долларов США
  • сумма, превышающая 40.000 долларов США
  • рассрочка менее 2
  • рассрочка более 18

Тестовый пример с жестко закодированными данными

Давайте предположим, что вы используете Selenium WebDriver для заполнения этой информации на веб-странице. Примером жестко закодированных данных может быть:

LoanPage loanPage = new LoanPage();

loanPage.fillName("Elias");
loanPage.fillEmail("elias@eliasnogueira.com");
loanPage.fillAmount(new BigDecimal(10.000));
loanPage.fillInstallments(8);

loanPage.clickOnSubmit();

В приведенном выше примере используется Java и шаблон объекта страницы для заполнения формы на веб-странице. Обратите внимание, что со строк 3 по 6 мы используем фиксированные данные для заполнения формы.

Использование фиксированных данных в тесте считается плохой практикой, и ее следует избегать, чтобы сократить объем обслуживания в автоматизированном тестовом коде.

Как это реализовать?

Есть несколько шагов, которым мы должны следовать:

  1. Создайте объект для моделирования необходимых вам данных
  2. Создайте класс builder
  3. Создайте фабричный класс для использования данных
  4. Измените класс для создания динамических данных
  5. Используйте заводской класс в тесте

Создайте объект для моделирования необходимых вам данных

В нашем примере мы заполняем форму кредита на основе имени, адреса электронной почты, суммы и платежей. Нам нужно создать объект (класс) для записи этой информации.

В простом классе Java мы можем смоделировать наш пример следующим образом:

public class Loan {

    // private attributes
    private String name;
    private String email;
    private BigDecimal amount;
    private int installments;

    // constructor
    public LoanData(String name, String email, BigDecimal amount, int installments) {
        this.name = name;
        this.email = email;
        this.amount = amount;
        this.installments = installments;
    }

    // getters and setters
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    // others getters and setters ignored (but they're necessary)

    @Override
    public String toString() {
        return "Loan{ \"name='" + name + '\'' +
                ", email='" + email + '\'' +
                ", amount=" + amount +
                ", installments=" + installments + '}';
    }
}

Когда мы создаем класс модели с использованием Java, нам нужны три вещи: частные атрибуты, конструктор и получатели и установщики.

Нам нужно создать те же атрибуты, которые мы собираемся использовать для заполнения данных. Вы можете увидеть это в строках с 4 по 7.

Конструктор необходим для создания объекта и простой передачи данных, но мы собираемся использовать его для создания нашего класса builder. Вы можете увидеть это в строках с 10 по 14.

Получатели и установщики могут использоваться для получения или установки отдельных данных в объекте. Вы можете увидеть это в строках с 19 по 25.

Строки с 28 по 33 показывают метод toString , который будет необходим для регистрации данных, которые мы будем использовать в тестах.

Возможно, вам не понадобятся геттеры и сеттеры, если мы планируем использовать объект builder, чтобы вы могли удалить его и установить атрибуты как окончательные, но вам все равно понадобятся конструктор и метод toString.

Класс model будет использоваться в качестве примера ниже, но мы сделаем его более читаемым и плавным с помощью шаблона builder.

Loan loan = new Loan("elias", "elias@eliasnogueira.com", new BigDecimal(10.000), 8);

Создайте класс builder

Вы могли бы использовать геттеры и сеттеры в классе Loan (если вы его не удалили) для создания класса с данными, но у нас есть лучший и простой способ сделать это: шаблон builder .

Я бы рекомендовал вам прочитать ссылку ниже, но, в целом, и для этого примера конструктор состоит из тех же атрибутов, что и в классе Loan , методов, которые получают атрибут в качестве параметра и возвращают класс builder, и метода сборки, который создаст конкретный класс.

Давайте изучим внутреннюю структуру.

public class LoanBuilder {

    private String name;
    private String email;
    private BigDecimal amount;
    private int installments;

    public LoanBuilder name(String name) {
        this.name = name;
        return this;
    }

    public LoanBuilder email(String email) {
        this.email = email;
        return this;
    }

    public LoanBuilder amount(BigDecimal amount) {
        this.amount = amount;
        return this;
    }

    public LoanBuilder installments(int installments) {
        this.installments = installments;
        return this;
    }

    public Loan build() {
        return new Loan(name, email, amount, installments);
    }
}

Строки с 3 по 6 имеют те же атрибуты, что и класс Loan . Он нам нужен для создания класса с заполненными параметрами с помощью его конструктора.

Строки с 8 по 26 – это методы построения. Метод должен возвращать класс builder, иметь параметр, связывать параметр с атрибутом и возвращать себя ( this ). Обычно имя метода совпадает с данными, которые вы заполняете.

В строках с 28 по 30 показан метод построения. Этот метод отвечает за создание основного объекта, которым в нашем случае является Loan. Он использует все значения атрибутов, используемые с помощью методов для его создания, где он вернет новый объект Loan .

В нем вы можете легко создать класс с данными, например:

public class MyTest {

    public static void main(String[] args) {

        // create a new Loan object using the LoanBuilder
        Loan loan = new LoanBuilder().
                name("elias").
                email("elias@eliasnogueira.com").
                amount(new BigDecimal(10.000)).
                installments(8).
                build();

        // show the loan data
        System.out.println("loan = " + loan);
    }
}

Обратите внимание, что мы можем использовать Loan Builder для цепочки методов, поскольку он возвращает сам себя, заполняя необходимые данные и всегда создавая их с помощью метода build .

Создайте фабричный класс для использования данных

Класс factory data немного отличается от шаблона Factory (на самом деле он проще), где у нас есть следующие аспекты для реализации:

  • частный конструктор, позволяющий избежать создания экземпляра класса
  • статический метод, который будет генерировать данные
    • поскольку он генерирует данные de, он должен вернуть их
    • метод должен возвращать модель данных

В приведенном ниже примере у нас есть различные заводские методы для создания кредита ( create Loan ), создания кредита с недопустимым e-mail ( createLoanWithNotValidEmail ) и другие.

Обратите внимание, что мы используем Loan Builder , чтобы легко добавлять правильные данные к атрибутам, возвращая объект Loan со всеми необходимыми данными.

public class LoanDataFactory {

    private LoanDataFactory() {}

    public static Loan createLoan() {
        return new LoanBuilder().name("Elias").email("elias@eliasnogueira.com")
                .amount(new BigDecimal("10.000")).installments(8).build();
    }

    public static Loan createLoanWithoutName() {
        return new LoanBuilder().email("elias@eliasnogueira.com")
                .amount(new BigDecimal("10.000")).installments(8).build();
    }

    public static Loan createLoanWithNotValidEmail() {
        return new LoanBuilder().name("Elias").email("not-valid-email")
                .amount(new BigDecimal("10.000")).installments(8).build();
    }

    public static Loan createLoanWithAmountLessThan() {
        return new LoanBuilder().name("Elias").email("elias@eliasnogueira.com")
                .amount(new BigDecimal("900.00")).installments(8).build();
    }

    // other data factories ignored
}

Как вы можете видеть, данные все еще жестко закодированы. Все в порядке но мы можем немного улучшить его, добавив динамическое поколение.

Измените класс для создания динамических данных

Мы можем динамически генерировать данные различными способами. Тремя основными из них являются:

  • использование библиотеки
  • использование конечной точки API
  • использование базы данных

Я сосредоточусь на первом: использовании библиотеки.

Для этого я представлю вам JavaFaker , это библиотека, которая может генерировать поддельные случайные данные при каждом вызове. Например: если вы сгенерируете имя, все сгенерированные имена будут разными.

public class LoanDataFactory {

    private static Faker faker;
    private static final int MIN_VALID_INSTALLMENTS = 2;
    private static final int MAX_VALID_INSTALLMENTS = 18;
    private static final int MAX_NUMBER_OF_DECIMALS = 2;
    private static final Long MIN_VALID_AMOUNT = Long.valueOf("1000");
    private static final Long MAX_VALID_AMOUNT = Long.valueOf("40000");

    private LoanDataFactory() {
        faker = new Faker();
    }

    public static Loan createLoan() {
        return new LoanBuilder().
                name(faker.name().firstName()).
                email(faker.internet().emailAddress())
                .amount(BigDecimal.valueOf(
                        faker.number().randomDouble(
                                MAX_NUMBER_OF_DECIMALS, MIN_VALID_AMOUNT, MAX_VALID_AMOUNT)))
                .installments(faker.number().numberBetween(MIN_VALID_INSTALLMENTS, MAX_VALID_INSTALLMENTS)).build();
    }

    // other methods ignored
}

Как вы можете видеть в приведенном выше коде, жестко закодированные данные были заменены использованием JavaFaker. Вы будете получать разные данные каждый раз, когда будете вызывать заводской метод, но это все еще действительные данные.

Константы, созданные со строки 4 по 8, были добавлены, чтобы добавить больше ясности и сократить время обслуживания при изменении значений в будущем.

Вы можете видеть со строки 16 по 21 использование Java Faker для генерации правильного значения для каждого поля. Например, адрес электронной почты добавляется в объект Loan с помощью faker.internet().адрес электронной почты() , где он генерирует действительное электронное письмо.

Используйте заводской класс в тесте

Я объяснил в тестовом примере с жестко закодированными данными о том, как выглядит этот класс. Давайте теперь воспользуемся подходом Фабрики тестовых данных, который мы изучили.

@Test
void submitValidLoan() {

    Loan validLoanData = LoanDataFactory.createLoan();
    LoanPage loanPage = new LoanPage();

    loanPage.fillName(validLoanData.getName());
    loanPage.fillEmail(validLoanData.getEmail());
    loanPage.fillAmount(validLoanData.getAmount());
    loanPage.fillInstallments(validLoanData.getInstallments());

    loanPage.clickOnSubmit();
}

Строка 4 показывает использование метода фабрики данных create Loan() , где возвращаемому объекту присваивается атрибут valid Loan Data .

В строках с 7 по 10 показано использование объекта Loan ( действительные данные о кредите ) для заполнения всех данных с использованием средств получения. Данные будут отличаться каждый раз, когда мы запускаем тест.

Реальные примеры

Хотели бы вы увидеть реальные примеры для двух разных целей тестирования: web и API?

Сеть

В проекте selenium-java-lean-test-architecture вы найдете класс Фабрика данных бронирования , который генерирует данные для бронирования номера.

Обратите внимание, что у меня есть ограничение: во внешнем интерфейсе у меня есть фиксированные данные по странам и ежедневному бюджету. Мы все еще можем рандомизировать его и заставить класс factory возвращать случайные данные для ограниченного набора данных.

интерфейс прикладного программирования

В проекте restassured-complete-basic-example вы найдете различные подходы к генерации данных в пакете data . Класс Simulation Data Factory имеет полный набор заводских методов для всех возможных сценариев.

В некоторых случаях вы даже можете вызвать некоторые существующие конечные точки для предоставления данных, необходимых для использования в ваших тестах. Это относится и к методу получить все симуляции из Api() где я получаю существующую симуляцию, используя ее в one Existing Simulation() factory метод для получения случайной существующей симуляции и в allExistingSimulations() для возврата всех существующих симуляций.

Оригинал: “https://dev.to/eliasnogueira/test-data-factory-why-and-how-to-use-4h5j”