テストデータ工場:理由と使用方法


このポストはHow to create Lean Test Automation Architecture for Web using Java シリーズ前の記事を見ていない場合は、それらをチェックしてください!

どのような問題を解決するのですか?
テストオートメーション中の最大の痛み点の一つは、テストしている層が何であれ、テストデータを管理することです.私は、ユニットとインテグレーションレベルで管理するのはとても簡単だと言います、そこで、我々はアプリケーション状態をコントロールすることができます、しかし、機能的でe 2 eテストのために、それは全く難しいです.
私たちが手動でコードファイルまたはCSVファイルまたはJSONファイルのような外部ソースからのデータを手動で変更を停止することができれば素晴らしいでしょうか?
データの変更によるコードのメンテナンスとテストの失敗を解決し、テストデータを生成する簡単で拡張可能な方法を作成します.

どのようなテストデータ工場ですか?
私たちはテスト用語に関する合意を持っていません(はい、私は知っています)、そして、我々はテストデータファクトリアプローチのための定義を持っていません.
いくつかの研究*(私は“Googleを使用していた”としてこれを読んで)私は同じコンセプトに関連する興味深い記事を見つけましたObjectMother パターン
研究
  • 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


  • あなたがこれらの2つの要件を持っているローンを取得するフォームで記入する必要がありますアプリケーションを持っていると思う:
  • NULLでない名前
  • 有効電子メール
  • 金額は、$ 1.000より大きくなければならなくて
  • 分割払いは2より大きく、10未満でなければなりません
  • あなたが既にいくつかのテスト技術を知っているならば、あなたはBoundary Value Analysis (BVA) 量と割賦入力のための試験技術
    もちろん、いくつかのデータを使用して、これらの可能なシナリオをテストする方法を理解しなければなりません.
  • 有効情報
  • 名前をNULL
  • 有効なメール
  • $ 1.000未満の量
  • 44000ドルより大きい額
  • 2未満のインストール
  • 18より大きいインストール

  • ハードコードデータのテスト例
    あなたがウェブページでこの情報を満たすためにセレンWebdriverを使っていると仮定しましょう.ハードコード化されたデータの例は次のようになります.
    LoanPage loanPage = new LoanPage();
    
    loanPage.fillName("Elias");
    loanPage.fillEmail("[email protected]");
    loanPage.fillAmount(new BigDecimal(10.000));
    loanPage.fillInstallments(8);
    
    loanPage.clickOnSubmit();
    
    上記の例では、Javaページとページオブジェクトパターンを使用してWebページのフォームを入力します.3行目から6行目までは、フォームを埋めるために固定データを使用しています.
    テストで固定データを使用することは悪い習慣と考えられて、自動テストコードでより少ないメンテナンスをするために避けられなければなりません.

    どのようにそれを実装するには?
    あとに続くいくつかのステップがあります.
  • 必要なデータをモデル化するオブジェクトを作成する
  • ビルダークラス
  • データを消費するファクトリクラスを作成する
  • クラスを変更して動的データを生成する
  • テストでファクトリクラスを使用する

  • 必要なデータをモデル化するオブジェクトを作成する
    私たちの例では、名前、電子メール、量、および割賦に基づいて融資フォームを充填している.この情報を記録するためにオブジェクト(クラス)を作成する必要があります.
    プレーン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行目までです.
    コンストラクタはオブジェクトを作成し、簡単にデータを通知する必要がありますが、ビルダークラスを生成するために使用します.10行目から14行目でご覧いただけます.
    ゲッターとセッターを使用して、オブジェクト内の単一のデータを取得または設定できます.19行目から25行目でご覧いただけます.
    28行目から33行目はtoString テストで使用するデータをログに記録するために必要なメソッドです.
    Builderオブジェクトを使用して、削除することができますし、属性を最後に設定する場合は、取得メソッドと設定メソッドを必要としないかもしれませんが、コンストラクターとToStringメソッドが必要です.
    モデルクラスは以下の例として使用されますが、ビルダーパターンを使用して読みやすく、流暢になります.
    Loan loan = new Loan("elias", "[email protected]", new BigDecimal(10.000), 8);
    

    ビルダークラス
    あなたは、gettersとセッターを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 オブジェクト.
    その中で、次のように流暢な方法でデータを持つクラスを作成できます.
    public class MyTest {
    
        public static void main(String[] args) {
    
            // create a new Loan object using the LoanBuilder
            Loan loan = new LoanBuilder().
                    name("elias").
                    email("[email protected]").
                    amount(new BigDecimal(10.000)).
                    installments(8).
                    build();
    
            // show the loan data
            System.out.println("loan = " + loan);
        }
    }
    
    我々が使用できることに注意してくださいLoanBuilder メソッドをチェインするには、必要に応じてデータを入力し、build メソッド.

    データを消費するファクトリクラスを作成する
    ファクトリデータクラスはファクトリパターンとは少し異なります(実際には単純です).ここで実装するには以下のような側面があります:
  • クラスインスタンスを避けるためのプライベートコンストラクター
  • データを生成する静的メソッド
  • データを生成するにつれて
  • このメソッドはデータモデルを返さなければなりません
  • 以下の例では、融資を作成する別のファクトリメソッドがありますcreateLoan ), 無効な電子メールでローンを作成するcreateLoanWithNotValidEmail ), など.
    我々が使用していることに注意してくださいLoanBuilder 簡単にすべての必要なデータを使用してオブジェクトのローンを返す属性に正しいデータを追加します.
    public class LoanDataFactory {
    
        private LoanDataFactory() {}
    
        public static Loan createLoan() {
            return new LoanBuilder().name("Elias").email("[email protected]")
                    .amount(new BigDecimal("10.000")).installments(8).build();
        }
    
        public static Loan createLoanWithoutName() {
            return new LoanBuilder().email("[email protected]")
                    .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("[email protected]")
                    .amount(new BigDecimal("900.00")).installments(8).build();
        }
    
        // other data factories ignored
    }
    
    あなたはまだハードコード化されたデータを見ることができます.それは大丈夫です、しかし、我々はダイナミックな世代を加えることによってもう少しそれを改善することができます.

    クラスを変更して動的データを生成する
    我々は動的にさまざまな方法を使用してデータを生成することができます.主な三つは以下の通りです.
  • ライブラリの使用
  • APIエンドポイントの使用
  • データベースの使用
  • 私は最初の1つに焦点を当てる:ライブラリを使用します.
    そのために紹介しますJavaFaker , Aは、それが呼ばれるたびに偽のランダムデータを生成することができるライブラリです.たとえば、名前を生成すると、生成される名前はすべて異なります.
    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の使用によって各フィールドの正しい値を生成できます.たとえば、メールを使用してローンオブジェクトに追加されますfaker.internet().emailAddress() それが有効な電子メールを生成するところ.

    テストでファクトリクラスを使用する
    私は、テストクラスでこのクラスがどのように見えるかについて、ハードコード化されたデータで説明しました.私たちが学んだテストデータファクトリーアプローチを使いましょう.
    @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はデータファクトリメソッドの使用方法を示しますcreateLoan() 返されるオブジェクトがvalidLoanData 属性.
    7行目から10行目は、貸付オブジェクトの使用方法を示すvalidLoanData ) を取得します.テストを実行するたびに、データは異なります.

    実例
    あなたは2つの異なるテストターゲットのための実際の例を参照してくださいか?

    ウェブ
    selenium-java-lean-test-architecture プロジェクトを見つけるBookingDataFactory 部屋を予約するためのデータを生成するクラス.
    私は制限があることに注意してください:フロントエンドでは、私は国と毎日の予算のためのデータを固定している.我々はまだそれをランダム化することができます工場のクラスを返すデータの限られたセットのランダムなデータを返します.

    API
    プロジェクトでrestassured-complete-basic-example あなたは別のデータ生成のアプローチを見つけるdata パッケージ.The SimulationDataFactory クラスは、すべての可能なシナリオのために完全な工場メソッドをセットします.
    場合によっては、いくつかの既存のエンドポイントを呼び出すこともできます.それは方法の場合ですgetAllSimulationsFromApi() ここで私は既存のシミュレーションを取得しているoneExistingSimulation() 工場のメソッドは、ランダムな既存のシミュレーションを取得するallExistingSimulations() すべての既存のシミュレーションを返します.