2

背景ストーリー

私はソフトウェア会社で、複雑に絡み合った古いシステムを置き換えるテスト自動化フレームワークを開発しています。

私たちのシステムでは、ほとんどすべての操作でログインが必要になるため、@BeforeMethod、@DataProvider、および @Factory を使用してテストをセットアップするのが最善であると判断しました。ただし、いくつかの問題に遭遇しました。

サンプル テスト ケース

ソフトウェア システムが野球チームの名簿であるとしましょう。ユーザーが名前でチームメンバーを検索できることを確認するためにテストしたいと思います。

(注: 私は、BeforeMethods が特定の順序で実行されないことを認識しています。今のところ、それが処理されていると仮定してください。)

@BeforeMethod
public void setupSelenium() {
    // login with username & password
    // acknowledge announcements
    // navigate to search page
}

@Test(dataProvider="players")
public void testSearch(String playerName, String searchTerm) {
    // search for "searchTerm"
    // browse through results
        // pass if we find playerName
    // fail (Didn't find the player)
}

このテスト ケースでは、次のことを前提としています。

  • ユーザーはすでにログオンしています (おそらく BeforeMethod で)
  • ユーザーはすでに検索ページに移動しています (簡単、メソッドの前)
  • テストのパラメータは、前述のログインに関連付けられています

問題点

それでは、テスト ケースのパラメーターを処理する方法を試してみましょう。

アイデア#1

この方法により、データプロバイダーをユーザー名に関連付けることができ、特定のテスト ケースに複数のユーザーを使用できます。

@Test(dataProvider="players")
public void testSearch(String user, String pass, String name, String search) {
    // login with user/pass
    // acknowledge announcements
    // navigate to search page
    // ...
}

...しかし、すべての関数が 2 つの追加パラメーターを受け入れるようにする必要があるため、多くの繰り返しがあります。言うまでもなく、実際にはテストしたくない通知アナウンス機能もテストしています。

アイデア#2

それでは、ファクトリを使用して適切に初期化しましょう!

class BaseTestCase {

    public BaseTestCase(String user, String password, Object[][] data);

}

class SomeTest {

    @Factory
    public void ...

}

これにより、テスト ケースごとに 1 つのファクトリを作成する必要が生じます...ただし、テスト ケースごとに複数のユーザーを使用できます。

結論

私はアイデアから新鮮です。XML ファイルからデータをロードし、プログラムからメソッドを呼び出すという別のアイデアがありましたが、それはばかげています。

何か案は?

4

3 に答える 3

2

私はまだあなたの問題を理解しているかどうかわかりません...

2 回目の試み、つまりテスト ケースごとに @Factory を書かなければならないことに満足していませんか? それでは、基本クラスのコンストラクターに @Factory アノテーションを付けてみませんか? このように、サブクラスは super を呼び出すだけで完了です。

正確に何を達成しようとしていますか?

于 2010-06-01T20:55:28.127 に答える
2

まず、各テスト ケースでやりすぎているようです。たとえば、何かを検索している場合、なぜ検索の一部としてナビゲーションをテストする必要があるのでしょうか?

第二に、要件が不明確なようです。単一の検索用語を送信して単一の結果を返すテストを作成できますか? これが最初のテストになるようです。

第三に、承認されたセッション接続/オブジェクトをテストの要件にできないのはなぜですか? コードを見ると、HTTP 経由で何らかの呼び出しを行っているように見えます。そうでない場合でも、ユーザー名を渡して各リクエストを渡す必要があることを考えると、ある種のブローカーを使用してアプリにメッセージを送信する必要があるようです...全体を自動化しないのはなぜですか事前に承認された接続に沿ってリクエストを送信する方法を提供する「承認されたブローカー」オブジェクトに入れますか?

次に、承認されたブローカーをテストに渡して、メッセージの受け渡しを処理します。または、テスト前の (BeforeMethods?) 関数で承認されたブローカーを設定し、それをクラス メンバー変数として使用できるようにします。

于 2010-06-01T18:36:04.613 に答える
1

セデリック、

初日からアカウントを作成する必要がありました。実際には、古い投稿を編集したり、コメントに返信したりすることはできません (現時点では)。少し拡張してみます。

これまでに私が思いついたものの例を次に示します。私は自分の質問に答えたと思います...これは機能しますが、少し厄介です。

私の質問は今、すべてのテストを 1 つの工場で行っているということです。それはいくつかの理由で良くありません。1 つは、それらをすべて手動で追加する (または反射的に挿入する) 必要があることです。2 つ目は、基本的にすべてを 1 つのスイートとして実行する必要があることです。何か案は?

package example2;

import java.lang.reflect.Method;
import java.util.HashMap;
import org.testng.annotations.*;

public class WebTestBase {

  protected String host, username, password;
  protected HashMap<String, Object[][]> dataSet;

  public WebTestBase(String host, String username, String password, HashMap<String, Object[][]> dataSet) {
    this.host = host;
    this.username = username;
    this.password = password;
    this.dataSet = dataSet;
  }

  @DataProvider(name="dataSet")
  public Object[][] dataSet(Method m) {
    return dataSet.get(m.getName());
  }

  @BeforeMethod
  public void login() {
    System.out.println("Logging in to " + host + " with " + username + ":" + password);
  }

  @AfterMethod
  public void logout() {
    System.out.println("Logging out!");
  }
}

package example2;

import java.util.HashMap;

import org.testng.annotations.Factory;

public class WebTestFactory {
  @Factory
  public Object[] factory() {
    HashMap<String, Object[][]> dataSetOne = new HashMap<String, Object[][]>();
    dataSetOne.put("searchRoster", new Object[][] {
          {"mcguire", "McGuire, Mark"},
          {"ruth", "Ruth, Babe"}
        });

    HashMap<String, Object[][]> dataSetTwo = new HashMap<String, Object[][]>();
    dataSetTwo.put("addPlayer", new Object[][] {
          {"Sammy Sosa", 0.273}
        });

    Object[] tests = new Object[] { 
        new SearchTest("localhost", "user", "pass", dataSetOne),
        new AddTest("localhost", "user", "pass", dataSetTwo)
      };

    return tests;
  }
}

package example2;

import java.util.HashMap;
import org.testng.annotations.Test;

public class SearchTest extends WebTestBase {

  public SearchTest(String host, String username, String password,
      HashMap<String, Object[][]> dataSet) {
    super(host, username, password, dataSet);
  }

  @Test(dataProvider="dataSet")
  public void searchRoster(String searchTerm, String playerName) {
    System.out.println("Searching for " + searchTerm);
    System.out.println("I found " + playerName + " in the search results!");
  }

}

package example2;

import java.util.HashMap;

import org.testng.annotations.Test;

public class AddTest extends WebTestBase {

  public AddTest(String host, String username, String password,
      HashMap<String, Object[][]> dataSet) {
    super(host, username, password, dataSet);
  }

  @Test(dataProvider="dataSet")
  public void addPlayer(String playerName, double battingAvg) {
    System.out.println("Adding " + playerName + " with avg " + battingAvg);
  }
}
于 2010-06-03T15:27:54.523 に答える