2019年の過給テストのヒント:Java自動化テストチュートリアル

公開: 2022-03-11

毎年、世界中のテスト自動化エンジニアが最新のツールと手法を研究して、テスト自動化フレームワークをより安定し、より速く、より使いやすく、保守しやすくしています。 これは、社内でフレームワークを継続的に広く採用するために不可欠です。 一般に、肥大化した古いフレームワークはすぐに時代遅れになります。

この記事では、2019年に向けてフレームワークを更新する方法と、2020年に向けて準備する方法をいくつか見ていきます。フレームワークを改善するために、私は常に「問題点」に集中しています。 これらは、セットアップが複雑であるか、ほとんどの障害を引き起こす領域です。 簡素化または改善したい3つの主要な領域を特定しました。

  1. Seleniumグリッド
  2. 待つ
  3. Chrome DevTools

Selenium Gridはセットアップが難しいことで有名であり、警告なしに失敗する可能性があります。 ここで何が改善されたかを見たかったのです。 また、作成したテストの安定性を向上させるために、SeleniumAPIに新しいwaitsが追加されているかどうかを調査したいと思いました。 最後に、テスターのツールキットの不可欠な部分となっているSeleniumを介してChromeDevToolsとの対話を開始できるかどうかを確認したいと思いました。

ヒント1:SeleniumグリッドをDocker化する

Selenium Gridは、セットアップが難しく、不安定で、CIパイプラインにデプロイまたはバージョン管理するのが難しいことで有名です。 はるかに簡単で安定した保守可能な方法は、ビルド済みのSeleniumDockerイメージを使用することです。

注:この方法の1つの欠点は、Windowsオペレーティングシステムをコンテナー化することがまだできないため、IE(Internet Explorer)がサポートされていないことです。

セットアップ

起動して実行するには、まず、DockerとDockerComposeをマシンにインストールする必要があります。 Windows 10またはMacを実行している場合は、どちらもDockerデスクトップを介してインストールされます。

グリッドの開始

Docker Hubの公式Seleniumリポジトリには、Selenium Hub、Firefox、およびChromeノード用に事前に構築されたDockerイメージが含まれています。

ローカルのSeleniumグリッドでこれらを使用する最も簡単な方法は、プロジェクトのルートディレクトリ内にDockerComposeファイルを作成することです。 物事を単純にするために、ファイルdocker-compose.ymlという名前を付けます。

次のグリッドを作成する例を以下に含めました。

  • 単一のSeleniumハブ
  • 1つのChromeノード
  • 1つのFirefoxノード
#docker-compose.yml version: "3" services: selenium-hub: image: selenium/hub:3.141.59-neon container_name: selenium-hub ports: - "4444:4444" chrome: image: selenium/node-chrome:3.141.59-neon volumes: - /dev/shm:/dev/shm depends_on: - selenium-hub environment: - HUB_HOST=selenium-hub - HUB_PORT=4444 firefox: image: selenium/node-firefox:3.141.59-neon volumes: - /dev/shm:/dev/shm depends_on: - selenium-hub environment: - HUB_HOST=selenium-hub - HUB_PORT=4444

Docker Composeファイルには、グリッドのセットアップが記述されています。 Docker Composeファイルの作成の詳細については、公式ドキュメントを参照してください。

グリッドを起動するには、任意のターミナルウィンドウ(Windowsではpowershellまたはcmdウィンドウ)を使用して、プロジェクトのルートディレクトリから次のコマンドを実行します。

 docker-compose up

グリッドへの接続

ハブはローカルマシンのポート4444でリッスンしているため、通常とまったく同じ方法でSeleniumグリッドに接続できます。 これは、Chromeノードを使用するようにドライバーを設定した例です。

 // Driver.java protected static RemoteWebDriver browser; DesiredCapabilities cap = new DesiredCapabilities(); ChromeOptions chromeOptions = new ChromeOptions(); cap.setCapability(ChromeOptions.CAPABILITY, chromeOptions); cap.setBrowserName("chrome"); driver = new RemoteWebDriver(cap);

その後、TestNGライブラリを使用して、通常どおり複数のノードでテストを並行して実行できます。

各ノードで複数のブラウザを実行できる可能性があることに注意してください。 ただし、これはお勧めできません。ノードごとに1つのブラウザを使用することは、最適なパフォーマンスを得るためのベストプラクティスと見なされます。

追加のヒントとコツ

テストをデバッグできるようにブラウザーで何が起こっているかを確認したい場合は、 debugブラウザーノードをダウンロードするdocker-compose.ymlファイルのdebugバージョンを用意する価値があります。 これらにはVNCサーバーが含まれているため、テストの実行中にブラウザーを監視できます。

ブラウザをヘッドレスで実行して速度を上げることも可能で(通常の方法)、Seleniumはイメージのbaseバージョンも提供しているため、追加のソフトウェアをインストールする必要がある場合は、独自のイメージを作成できます。

CIパイプライン用のグリッドの安定バージョンを作成するために、グリッドをKubernetesまたはSwarmにデプロイすることもできます。 これにより、Dockerに障害が発生した場合でも、Dockerをすばやく復元または交換できます。

ヒント2:スマートウェイト

テスト自動化エンジニアなら誰でも知っているように、 waitsはテスト自動化フレームワークの安定性にとって非常に重要です。 また、 sleepspausesを冗長にすることでテストを高速化し、低速のネットワークやクロスブラウザの問題を克服することもできます。 以下は、 waitsをさらに回復力のあるものにするためのヒントです。

Java自動化テストチュートリアル#2:待機中の論理演算子:待機を具体的に指定する

ExpectedConditionsクラスは時間の経過とともに成長し、現在、考えられるほぼすべての状況を網羅しています。 多くの場合、 ExpectedConditions.presenceOfElementLocated(locator)で十分ですが、 ExpectedConditionクラス内のメソッドを使用して、 Actions.javaクラスに埋め込むことですべてのユーザーアクションをカバーすることをお勧めします。 これにより、ほとんどのクロスブラウザまたは低速のWebサイトの問題に対してテストを防弾できます。

たとえば、リンクをクリックすると新しいタブが開く場合は、 ExpectedConditions.numberOfWindowsToBe(2)を使用します。 これにより、タブに切り替える前にタブが確実に表示されます。

findElementsを使用するときに、 waitを使用して、ページに存在するすべての要素を確実にキャプチャすることもできます。 これは、 searchページが結果を返すのに時間がかかる場合に特に役立ちます。 たとえば、次の行です。

 List<WebElement> results = driver.findElements(locators.RESULTS);

検索結果がまだロードされていない場合は、 List配列が空になる可能性があります。 代わりに、 numberOfElementsToBeMoreThanの期待される条件を使用して、結果がゼロより大きくなるのを待つことをお勧めします。 例えば:

 WebElement searchButton = driver.findElement(locators.SEARCH_BUTTON); searchButton.click(); new WebDriverWait(driver, 30) .until(ExpectedConditions .numberOfElementsToBeMoreThan(locators.RESULTS, 0)); List<WebElement> results = driver.findElements(locators.RESULTS); results.get(0).click();

これで、 findElementsコマンドは、検索結果が返された後にのみ実行されます。

このwaitは、Seleniumでうまく機能しないフロントエンド(Angular Webサイトなど)を処理しているときに単一の要素を見つける場合にも役立ちます。 このようなメソッドを作成すると、テストが保護され、テストがはるかに安定します。

 protected static WebElement waitForElement(By locator){ try { new WebDriverWait(browser, 30) .until(ExpectedConditions .numberOfElementsToBeMoreThan(locator, 0)); } catch (TimeoutException e){ e.printStackTrace(); Assert.fail("Timeout: The element couldn't be found in " + WAIT + " seconds!"); } catch (Exception e){ e.printStackTrace(); Assert.fail("Something went wrong!"); } return browser.findElement(locator); }

要素が表示されなくなるのを待つことも可能です。 これは、テストを続行する前に[ OK ]または[ Save ]ボタンをクリックした後にポップアップが消えるのを待っている場合に特に便利です。

 WebElement okButton = driver.findElement(locators.OK_BUTTON); okButton.click(); new WebDriverWait(driver, 30) .until( ExpectedConditions .invisibilityOfElementLocated(locators.POPUP_TITLE) );

上記のすべての方法およびその他の方法は、公式ドキュメントに記載されています。 すべての可能性を読み、フレームワークの安定性を向上させるために10分を費やす価値は十分にあります。

Java自動化テストチュートリアル#2:待機中の論理演算子

waitsに回復力を組み込む良い方法は、論理演算子を使用することです。 たとえば、要素が配置されていること、および要素がクリック可能であることを確認する場合は、次のコードを使用します(これらの例はブール値を返すことに注意してください)。

 wait.until(ExpectedConditions.and( ExpectedConditions.presenceOfElementLocated(locator), ExpectedConditions.elementToBeClickable(locator) ) );

ページのタイトルが変更される可能性があるかどうかわからない場合は、OR演算子が適切です。 次に、最初の条件が失敗した場合にURLのチェックを含めて、正しいページにいることを確認できます。

 wait.until(ExpectedConditions.or( ExpectedConditions.titleIs(expectedTitle), ExpectedConditions.urlToBe(expectedUrl) ) );

または、ページでアクションが実行された後にチェックボックスが有効にならないようにする場合は、NOT演算子が適切です。

 wait.until(ExpectedConditions.not( ExpectedConditions.elementToBeClickable(locator) ) );

演算子を使用すると、 waitsの回復力が高まり、テストの脆弱性が低下します。

ヒント3:Chrome DevTools:ネットワーク状態のシミュレーション

ローカルホストまたはローカルネットワークでWebアプリを実行すると、実際に実行した場合のパフォーマンスについて誤った印象を与える可能性があります。 さまざまなアップロードおよびダウンロード速度を調整する機能により、タイムアウトによってアクションが失敗する可能性があるインターネット上でアプリケーションがどのように実行されるかについて、より適切に表現できます。 ChromeのDevToolsの機能を使用して、これをシミュレートし始めることができます。

次のコードは、さまざまなダウンロード速度とアップロード速度を使用してToptalホームページを開きます。 まず、次のコードを使用して、速度をTestNGデータプロバイダーに保存します。

 import org.testng.annotations.DataProvider; public class ExcelDataProvider { @DataProvider(name = "networkConditions") public static Object[][] networkConditions() throws Exception { return new Object[][] { // Upload Speed, Dowload Speed in kb/s and latency in ms. { 5000 , 5000, 5 }, { 10000, 7000, 5 }, { 15000, 9000, 5 }, { 20000, 10000, 5 }, { 0, 0 }, }; } }

注:アップロードとダウンロードのスロットリングの単位はkb/sで、待ち時間の単位はmsです。

次に、このデータを使用して、さまざまなネットワーク条件下でテストを実行できます。 テスト内で、 CommandExecutorはブラウザの現在のセッションでコマンドを実行します。 これにより、Chromeのデベロッパーツール機能で必要な設定がアクティブになり、低速のネットワークをシミュレートします。 一連のテストを実行するときに、 ifステートメント内のコードを@BeforeClassメソッドに含めることができます。

 import org.testng.annotations.Test; import com.google.common.collect.ImmutableMap; import java.io.IOException; import java.util.HashMap; import java.util.Map; import org.openqa.selenium.remote.Command; import org.openqa.selenium.remote.CommandExecutor; import org.openqa.selenium.remote.Response; public class TestClass { // load our data provider @Test(dataProvider = "networkConditions") public void test(int download, int upload, int latency) throws IOException { // only run if the network is throttled if (download > 0 && upload > 0) { CommandExecutor executor = driver.getCommandExecutor(); // create a hashmap of the required network conditions Map map = new HashMap(); // you can even test 'offline' behaviour map.put("offline", false); map.put("latency", latency); map.put("download_throughput", downloadThroughput); map.put("upload_throughput", uploadThroughput); // execute our code Response response = executor.execute( new Command(driver.getSessionId(), "setNetworkConditions", ImmutableMap.of("network_conditions", ImmutableMap.copyOf(map)))); } // Open the website driver.get("https://www.toptal.com/"); // You can then check that elements are loaded etc. // Don't forget to use waits! } }
関連:自信を持って構築する:JUnitテストのガイド

ボーナスのヒント:Cookieを管理する方法

ブラウザのCookieは、前のセッションから保存されているかどうかに応じて、アプリケーションでさまざまな動作を引き起こす可能性があります(たとえば、アプリケーションは、すでにログインしているユーザーで読み込まれる場合があります)。 各テストを実行する前にCookieをクリアして、問題が発生しないことを確認することをお勧めします。

以下のコードを使用すると、すべてのCookieを削除できます。

 driver.manage().deleteAllCookies();

名前でCookieを削除することもできます。

 driver.manage().deleteCookieNamed("CookieName");

または、Cookieの内容を取得します。

 String myCookie = driver.manage().getCookieNamed("CookieName").getValue();

または、すべてのCookieを取得します。

 List<Cookie> cookies = driver.manage().getCookies();

2020年のテスト自動化:将来を見据えて

Selenium 4は、今後数か月でリリースされます。 まだ開発中ですが、アルファ版がすでにリリースされているので、どのような改善が提供されるかを確認する価値があります。

注:ロードマップを確認することで、進捗状況を追跡できます。

W3CWebDriverの標準化

SeleniumはJSONワイヤープロトコルを介してブラウザーと通信する必要がなくなります。 代わりに、自動テストはブラウザと直接通信します。 これは、ブラウザーのアップグレードからの保護を含む、Seleniumテストの有名な不安定な性質に対処する必要があります。 うまくいけば、テスト速度も向上します。

よりシンプルなSeleniumグリッド

Seleniumグリッドは、Selenium 4でより安定し、セットアップと管理が容易になります。グリッドがノードとハブの組み合わせとして機能するため、ユーザーはハブとノードを個別にセットアップして起動する必要がなくなります。 さらに、Dockerのサポートが改善され、並列テストがネイティブに含まれ、より有益なUIが提供されます。 フックを使用したリクエストトレースは、グリッドのデバッグにも役立ちます。

ドキュメンテーション

Seleniumのドキュメントは、Selenium 2.0のリリース以降更新されていないため、非常に必要なオーバーホールが行われる予定です。

APIの変更

OperaおよびPhantomJSブラウザのサポートは削除されます。 ヘッドレス実行はChromeまたはFirefoxで実行でき、OperaはChromium上に構築されているため、このブラウザではChromiumテストで十分であると見なされます。

WebElement.getSize()およびWebElement.getLocation()は、単一のメソッドWebElement.getRect()に置き換えられました。 ただし、これらは単一の要素のスクリーンショットを作成するためによく使用されるため、Selenium4の要素のスクリーンショットをキャプチャするAPIコマンドもあることを知っておく価値があります。

WebDriver Windowの場合、 getPositionメソッドとgetSizeメソッドはgetRectメソッドに置き換えられ、 setPositionメソッドとsetSizeメソッドはsetRectメソッドに置き換えられます。 fullscreenminimizeのメソッドが利用可能になるため、これらのアクションはテスト内で実行できます。

その他の注目すべき変更:

  • すべてのブラウザのOptionsクラスは、 Capabilitiesクラスを拡張するようになりました。
  • フレームナビゲーションを容易にするために、 driver.switchTo().parentFrame()メソッドが追加されました。
  • 現在のものよりも高いレベルで動作するniceロケーターが含まれます。 それらはByのサブクラスになります。
  • DevTools APIが実装され、ユーザーはChromeデバッグプロトコル(および他のブラウザーの同等の機能)を使用して提供される機能を利用できるようになります。 これらには以下が含まれます:
    • フルページのスクリーンショット(オフスクリーン要素を含む)。
    • ストリーミングログ。
    • ページ上のミューテーションイベントを待機しています。
  • 非推奨のメソッドとクラスの多くも削除されます。

注: Selenium4のAlphaバージョンはMavenリポジトリーから入手できます。 これを現在のフレームワーク(理想的にはサンドボックスブランチで)に対して試してみることを強くお勧めします。そうすれば、変更の準備が整います。

結論

この記事では、テスト自動化フレームワークを改善したいくつかの領域について説明しました。 以前よりも安定して使用できるようになり、ソフトウェア配信のライフサイクルに関与するすべての人にプラスの影響を与えます。

上で概説した変更を加えることは良いスタートですが、フレームワーク全体で「問題点」を確認することを強くお勧めします。これは、私がカバーしていない改善点がある可能性があるためです。 たとえば、WebDriver Managerを使用してドライバーを管理していますか、それとも手動で更新していますか?

また、これを行う日付を少なくとも年に1回設定することをお勧めしますが、理想的には6か月ごとです。 この記事には、Selenium4.0で行われる変更が含まれています。 Seleniumのalpha版を自分で確認してください。 変化は劇的であり、あなたは準備する必要があります。 これがお役に立てば幸いです。 フレームワークで春の大掃除をしているときに新しい方法やテクニックを見つけた場合は、以下のコメントセクションに追加して、このブログの他の読者と共有してください。

また、Seleniumでの自動​​テスト、およびページオブジェクトモデルを使用して保守可能で再利用可能なテストルーチンを作成する方法を確認したい場合は、Seleniumでの自動​​化:ページオブジェクトモデルとページファクトリを確認してください。

関連: Dart言語:JavaとC#が十分にシャープでない場合