セレニティBDDと脚本

セレニティBDDと脚本

1. 概要

この記事では、SerenityBDDの脚本パターンについて簡単に説明します。 これを読む前に、まずbasics of Serenity BDDを読むことをお勧めします。 また、Serenity BDD integration with Springに関する記事も興味深いかもしれません。

Serenity BDDで導入された脚本は、チームがより堅牢で信頼性の高いテストを作成できるようにすることで、優れたテスト習慣と適切に設計されたテストスイートを奨励することを目的としています。 これは、Selenium WebDriverおよびPage Objectsモデルに基づいています。 introduction to Seleniumを読んだら、これらの概念はかなりなじみ深いものであることがわかります。

2. メーベン依存

まず、次の依存関係をpom.xmlファイルに追加しましょう。


    net.serenity-bdd
    serenity-junit
    1.4.0


    net.serenity-bdd
    serenity-screenplay
    1.4.0


    net.serenity-bdd
    serenity-screenplay-webdriver
    1.4.0

serenity-screenplayおよびserenity-screenplay-webdriverの最新バージョンは、Maven中央リポジトリーからフェッチできます。

脚本を実行するには、Webドライバーも必要です。ChromeDriverまたはMozilla-GeckoDriverのいずれかで実行できます。 この記事では、ChromeDriverを使用します。

WebDriverを有効にするには、次のプラグイン構成が必要です。webdriver.chrome.driverの値は、MavenプロジェクトのChromeDriverバイナリファイルの相対パスである必要があります。


    maven-failsafe-plugin
    2.20
    
        
            chromedriver
        
    

3. WebDriverのサポート

WebDriver変数に@Managedアノテーションをマークすることで、SerenityにWebDriverインスタンスを管理させることができます。 Serenityは、各テストの開始時に適切なドライバーを開き、テストが終了するとシャットダウンします。

次の例では、ChromeDriverを起動し、Googleを開いて「例」を検索します。 Eugenの名前が検索結果に表示されることを期待しています。

@RunWith(SerenityRunner.class)
public class GoogleSearchLiveTest {

    @Managed(driver = "chrome")
    private WebDriver browser;

    @Test
    public void whenGoogleexampleThenShouldSeeEugen() {
        browser.get("https://www.google.com/ncr");

        browser
          .findElement(By.name("q"))
          .sendKeys("example", Keys.ENTER);

        new WebDriverWait(browser, 5)https://www.example.com/serenity-screenplay
          .until(visibilityOfElementLocated(By.cssSelector("._ksh")));

        assertThat(browser
          .findElement(By.cssSelector("._ksh"))
          .getText(), containsString("Eugen (example)"));
    }
}

@Managedにパラメータを指定しない場合、SerenityBDDはこの場合Firefoxを使用します。 @Managedアノテーションによるサポートされているドライバーの全リスト:firefox, chrome, iexplorer, htmlunit, phantomjs

IExplorerまたはEdgeでテストする必要がある場合は、それぞれhere(for IE)およびhere(for Edge)からWebドライバーをダウンロードできます。 Safari WebDriverは、MacOSの/usr/bin/safaridriverでのみ使用できます。

4. ページオブジェクト

Serenity Pageオブジェクトは、WebDriverページオブジェクトを表します。 PageObjectは、再利用のためにWebDriverの詳細を非表示にします。

4.1. PageObjectを使用したリファクタリングの例

最初にPageObjectを使用して、要素の検索、検索、結果検証のアクションを抽出することにより、以前のテストを改良しましょう。

@DefaultUrl("https://www.google.com/ncr")
public class GoogleSearchPageObject extends PageObject {

    @FindBy(name = "q")
    private WebElement search;

    @FindBy(css = "._ksh")
    private WebElement result;

    public void searchFor(String keyword) {
        search.sendKeys(keyword, Keys.ENTER);
    }

    public void resultMatches(String expected) {
        assertThat(result.getText(), containsString(expected));
    }
}

WebElementはHTML要素を表します。 インターフェイスのAPIを介してWebページと対話できます。 上記の例では、ページ内のWeb要素を見つける2つの方法を使用しました。要素名と要素のCSSクラスです。

タグ名による検索、リンクテキストによる検索など、Web要素を検索する際に適用する方法は他にもあります。 詳細については、guide to Seleniumを参照してください。

WebElementWebElementFacadeに置き換えることもできます。これにより、Web要素を処理するためのより流暢なAPIが提供されます。

Serenity will automatically instantiate any PageObject fields in the JUnit testとして、前のテストをはるかにクリーンなテストに書き直すことができます。

@RunWith(SerenityRunner.class)
public class GoogleSearchPageObjectLiveTest {

    @Managed(driver = "chrome")
    private WebDriver browser;

    GoogleSearchPageObject googleSearch;

    @Test
    public void whenGoogleexampleThenShouldSeeEugen() {
        googleSearch.open();

        googleSearch.searchFor("example");

        googleSearch.resultMatches("Eugen (example)");
    }
}

これで、GoogleSearchPageObjectを変更せずに、他のキーワードを使用して検索し、関連する検索結果を照合できます。

4.2. 非同期サポート

現在、多くのWebページが動的に提供またはレンダリングされています。 このような場合に対処するために、PageObjectは、要素のステータスを検査できるようにする多くの豊富な機能もサポートしています。 We can check if the elements are visible, or wait until they are visible before proceeding.

表示したい要素が表示されるようにして、resultMatchesメソッドを拡張しましょう。

public void resultMatches(String expected) {
    waitFor(result).waitUntilVisible();
    assertThat(result.getText(), containsString(expected));
}

あまり長く待つことを期待しない場合は、待機中のアクションのタイムアウトを明示的に指定できます。

public void resultMatches(String expected) {
    withTimeoutOf(5, SECONDS)
      .waitFor(result)
      .waitUntilVisible();
    assertThat(result.getText(), containsString(expected));
}

5. 脚本パターン

Screenplay Patternは、SOLID設計原則を自動受け入れテストに適用します。 脚本パターンの一般的な理解は、given_when_thenのコンテキストで次のように説明できます。

  • given –いくつかのTaskを実行できるActor

  • whenActorTaskを実行します

  • then –Actorは効果を確認し、結果を確認する必要があります

次に、前のテストシナリオを脚本パターンに当てはめましょう。Googleを使用できるユーザーキティがGoogleで「例」を検索すると、キティは結果にユーゲンの名前を表示するはずです。

最初に、Kittyが実行できるタスクを定義します。

  1. キティはGoogleを使用できます。

    public class StartWith implements Task {
    
        public static StartWith googleSearchPage() {
            return instrumented(StartWith.class);
        }
    
        GoogleSearchPage googleSearchPage;
    
        @Step("{0} starts a google search")
        public  void performAs(T t) {
            t.attemptsTo(Open
              .browserOn()
              .the(googleSearchPage));
        }
    }
  2. キティはGoogleで検索できます。

    public class SearchForKeyword implements Task {
    
        @Step("{0} searches for '#keyword'")
        public  void performAs(T actor) {
            actor.attemptsTo(Enter
              .theValue(keyword)
              .into(GoogleSearchPage.SEARCH_INPUT_BOX)
              .thenHit(Keys.RETURN));
        }
    
        private String keyword;
    
        public SearchForKeyword(String keyword) {
            this.keyword = keyword;
        }
    
        public static Task of(String keyword) {
            return Instrumented
              .instanceOf(SearchForKeyword.class)
              .withProperties(keyword);
        }
    }
  3. キティはGoogleの検索結果を見ることができます:

    public class GoogleSearchResults implements Question> {
    
        public static Question> displayed() {
            return new GoogleSearchResults();
        }
    
        public List answeredBy(Actor actor) {
            return Text
              .of(GoogleSearchPage.SEARCH_RESULT_TITLES)
              .viewedBy(actor)
              .asList();
        }
    }

また、Google検索PageObjectはすでに定義されています。

@DefaultUrl("https://www.google.com/ncr")
public class GoogleSearchPage extends PageObject {

    public static final Target SEARCH_RESULT_TITLES = Target
      .the("search results")
      .locatedBy("._ksh");

    public static final Target SEARCH_INPUT_BOX = Target
      .the("search input box")
      .locatedBy("#lst-ib");
}

これで、メインのテストクラスは次のようになります。

@RunWith(SerenityRunner.class)
public class GoogleSearchScreenplayLiveTest {

    @Managed(driver = "chrome")
    WebDriver browser;

    Actor kitty = Actor.named("kitty");

    @Before
    public void setup() {
        kitty.can(BrowseTheWeb.with(browser));
    }

    @Test
    public void whenGoogleexampleThenShouldSeeEugen() {
        givenThat(kitty).wasAbleTo(StartWith.googleSearchPage());

        when(kitty).attemptsTo(SearchForKeyword.of("example"));

        then(kitty).should(seeThat(GoogleSearchResults.displayed(),
          hasItem(containsString("Eugen (example)"))));
    }
}

このテストの実行後、テストレポートでキティが実行した各ステップのスクリーンショットが表示されます。

image

6. 概要

この記事では、Serenity BDDでScreenplay Patternを使用する方法を紹介しました。 また、PageObjectを使用すると、WebDriverと直接対話する必要がないため、テストの読み取り、保守、拡張が容易になります。

Serenity BDDのPageObjectと脚本パターンの詳細については、Serenityドキュメントの関連セクションを確認してください。

いつものように、完全なサンプルコードはon the Githubにあります。