自転車から...

こんにちは



この短いエッセイは、Webおよびモバイルアプリケーションのテストの自動化に関与するスペシャリストおよび主に開発者であるQAを対象としています。 オープンソースに興味がある人も大歓迎です。



ここでは、1年前に記事「セレンと1つの「自転車」について」で表現された考えを発展させたいと思います。



計画:

1.主な機能(ショートレビュー)

2.展開方法(叙情的余談)

3.結論。



すぐに解決策慣れることができます 。 しかし、あなたが最初に記事を読むことに興味があるなら-

行こう!







1.主な機能(ショートレビュー)







既に理解しているように、ソリューションはJava 8で記述されています。主なコンポーネントは、Selenium(デスクトップブラウザーとの対話を保証する)、 Appiumjava-client 、モバイルブラウザーとアプリケーションとの対話を保証する)です。



Selenium Webdriverを操作する原理と方法について説明する場合、YandexThucydidesの Html要素などのソリューションで提供されるものと多少似ています。 しかし、これらはすべて多少修正されています。



何が起こった、私はいくつかの節足動物との関係を持っています。 SeleniumとAppiumがテストの自動化でアプリケーションを見つけることを考えると、バグという言葉の翻訳を知っています。これはソリューションの名前です-Arachnidium(lat。 "Arachnid")。



だから。



ブラウザー間の互換性




この点は当たり前だと思います。 しかし、言及する必要があります。



以下がサポートされています。

-Firefox;

-クロム;

-Internet Explorer;

-サファリ;

-PhantomJS。

-上記のブラウザーのリモート起動。

HtmlUnitDriverおよびOperaDriverは放棄されなければなりませんでした。 1つ目はRemoteWebDriverの後継者ではなく、そのサポートは松葉杖でいっぱいで、2つ目は時代遅れです(たとえば、Windows 8 / 8.1でOperaを起動しません)。 しかし、実際の代替品があります:

-Android向けChrome。 少し後で、ネイティブAndroidブラウザとChromiumのサポートを追加したい

-iOS用モバイルSafari



ネイティブおよびハイブリッドモバイルアプリケーションのUIとの対話の自動化のサポート。






これは、Appiumの機能を集中的に使用するために可能です。



しかし、私の意見では、これでさえ最も興味深いものではありません。



アプリケーションのユーザーインターフェイスを部分的および全体的にシミュレートする機能。




ここここここ (英語)でこれらの原則について詳しく説明しました 。 しかし、読者の注意をそらさないために、私はおそらくもっと壮大な何かを引用します。



Androidテストでは、BBC Newsアプリを使用します。 そのUIは、要素の視覚的構成の点でサイトのUIに非常に似ています。 サイトとAndroidアプリの両方をテストするとします。 次に、このようなユーザーインターフェイスを記述できます。



ニュースのリストと表示:



カットの下のコード
/** * Imagine that we have to check browser and Android versions * How?! See below. */ @IfBrowserURL(regExp = "http://www.bbc.com/news/") @IfMobileContext(regExp = "NATIVE_APP") @IfMobileAndroidActivity(regExp = "HomeWwActivity") public class BBCMain extends FunctionalPart<Handle>{ @FindBy(className = "someClass1") @AndroidFindBy(id = "bbc.mobile.news.ww:id/articleWrapper") private List<RemoteWebElement> articles; @FindBy(className = "someClass2") @AndroidFindBy(id = "bbc.mobile.news.ww:id/articleWebView") private RemoteWebElement currentArticle; @FindBy(className = "someClass3") @AndroidFindBy(id = "bbc.mobile.news.ww:id/optMenuShareAction") private RemoteWebElement share; @FindBy(className = "someClass4") @AndroidFindBy(id = "bbc.mobile.news.ww:id/optMenuWatchListenAction") private RemoteWebElement play; @FindBy(className = "someClass5") @AndroidFindBy(id = "bbc.mobile.news.ww:id/optMenuEditAction") private RemoteWebElement edit; @FindBy(className = "someClass6") @AndroidFindBy(uiAutomator = "new UiSelector().resourceId" + "(\"bbc.mobile.news.ww:id/optMenuRefreshAction\")") private RemoteWebElement refresh; protected BBCMain(Handle context) { super(context); load(); } @InteractiveMethod public int getArticleCount(){ return articles.size(); } //some more staff //... }
      
      









カテゴリー別ニュースレター:



カットの下のコード
 /** * Imagine that we have to check browser and Android versions * How?! See below. */ @IfBrowserURL(regExp = "http://www.bbc.com/news/") @IfMobileContext(regExp = "NATIVE_APP") @IfMobileAndroidActivity(regExp = "PersonalisationActivity") public class TopicList extends FunctionalPart<Handle> { @CacheLookup @FindBys({@FindBy(linkText = "someLink"), @FindBy(linkText = "someLink2"), @FindBy(linkText = "someLink2")}) @AndroidFindBys({@AndroidFindBy(id = "bbc.mobile.news.ww:id/personalisationListView"), @AndroidFindBy(className = "android.widget.LinearLayout"), @AndroidFindBy(uiAutomator = "new UiSelector()"+ ".resourceId(\"bbc.mobile.news.ww:id/feedTitle\")")}) private List<WebElement> titles; @CacheLookup @FindBys({@FindBy(linkText = "someLink3"), @FindBy(linkText = "someLink4"), @FindBy(linkText = "someLink5")}) @AndroidFindBys({@AndroidFindBy(id = "bbc.mobile.news.ww:id/personalisationListView"), @AndroidFindBy(className = "android.widget.LinearLayout"), @AndroidFindBy(uiAutomator = "new UiSelector()."+ "className(\"android.widget.CheckBox\")")}) private List<WebElement> checkBoxes; @AndroidFindBy(id = "bbc.mobile.news.ww:id/personlisationOkButton") private WebElement okButton; protected TopicList(Handle context) { super(context); load(); } //some more staff //... }
      
      









テスト(最も単純化されたビュー):



Android



カットの下のコード
  @Test public void androidNativeAppTest() { Configuration config = Configuration .get("android_bbc.json"); Application<?,?> bbc = MobileFactory.getApplication( Application.class, config); try { BBCMain bbcMain = bbc.getPart(BBCMain.class); Assert.assertNotSame(0, bbcMain.getArticleCount()); bbcMain.selectArticle(1); Assert.assertEquals(true, bbcMain.isArticleHere()); bbcMain.edit(); TopicList<?> topicList = bbcMain.getPart(TopicList.class); topicList.setTopicChecked("LATIN AMERICA", true); topicList.setTopicChecked("UK", true); topicList.ok(); bbcMain.edit(); topicList.setTopicChecked("LATIN AMERICA", false); topicList.setTopicChecked("UK", false); topicList.ok(); } finally { bbc.quit(); } }
      
      









ブラウザ(デスクトップ/モバイル)



カットの下のコード
 @Test public void webTest() { Configuration config = Configuration .get("android_some_browser.json"); Application<?,?> bbc = WebFactory.getApplication( Application.class, config, urlToBBCNews); //does the same
      
      









いくつかのことについては後で説明します。



私はユニバーサル(むしろ条件付きユニバーサル)モデルを実装しようとしました。そのため、自動テストのフレームワークの開発者は(この役割で自分自身を見て、自分ではひどくできません:))コードを増やしませんでしたが、環境から独立させることができました(私はこれを理解していますテストの実行方法-ブラウザーで実行するか、ハイブリッドアプリケーションのネイティブコンテンツ/ htmlコンテンツであるか)。



使用済みデザイン-ページオブジェクトパターン。 私のバージョンでは、繰り返しのウィジェットまたは要素のセットがある場合、ページ/スクリーンショットの全体または一部を記述できると想定しています。 アプリケーション全体をページオブジェクトのように動作させることもできます!



別の機能は、複数のブラウザーウィンドウ(またはモバイルアプリケーションの場合はコンテキスト)があり、コンテンツの一部がiframsに配置される状況でWebDriverのインスタンスを管理する必要性に関連する多くの技術的なニュアンスが自動化されることです。 したがって、ビジネスロジックの説明に完全に集中できます。



建築






私の私見である現代の状況では、決定するのはモノリシックアーキテクチャではなく、モジュール式または「透明」です。 標準のSeleniumAppiumの両方のソリューションを使用できるようにすべてを実装しようとしました(このソリューションの要素を装飾するこの方法はデフォルトで使用されます)。そのために、便利な作業方法と、理論的にはサードパーティのソリューションを提供しようとしました



以下に例を示します。



-YandexのHtmlElementsとのコラボレーション。 リンク

-CodeborneのSelenideとのコラボレーション。 リンク

-トゥキュディデスの使用。 リンク 誰が気にするか-Web向けレポート (GoogleDrive)とAndroid向けレポート (BBC News、AndroidタブレットをエミュレートするGenymotion仮想マシン)。 視聴を楽しみ、解凍することを忘れないでください。 アリュールのサンプルを後で作成したいと思います。



設定方法


この場合、ブラウザーとモバイルアプリケーションを起動するためのパラメーターを転送および保存することを意味します(最初から意図したとおり)。 ここで詳細に説明します 。 しかし、どうするか。 例を挙げましょう。



プロジェクトに添付されているsettings.jsonファイルに保存されている一般的な設定があるとします



デフォルトのパラメーターを持つJSON
 { "settingA": { "aValue":{ "type":"STRING", "value":"AAA" } }, "settingB": { "bValue":{ "type":"STRING", "value":"bbb" } }, "settingC": { "cValue":{ "type":"STRING", "value":"C" } }, "settingD": { "dValue":{ "type":"STRING", "value":"D..." } } }
      
      









また、別の名前のファイルがあります。このファイルには、上記の例のデータと重複するデータが含まれています。



カスタムパラメータを持つJSON
 { "settingB": { "bValue":{ "type":"INT", "value":"1" } }, "settingC": { "cValue":{ "type":"BOOL", "value":"true" } } }
      
      









以下のコード



コード
 import com.github.arachnidium.util.configuration.Configuration; import org.junit.Before; import org.junit.Test; public class DemoTest { Configuration testConfig; private String aGroup = "settingA"; private String bGroup = "settingB"; private String cGroup = "settingC"; private String dGroup = "settingD"; private String aValue = "aValue"; private String bValue = "bValue"; private String cValue = "cValue"; private String dValue = "dValue"; @Before public void setUp() throws Exception { testConfig = Configuration.get("src/test/resources/test.json"); } @Test public void test() { Object a = Configuration.byDefault.getSettingValue(aGroup, aValue); Object b = Configuration.byDefault.getSettingValue(bGroup, bValue); Object c = Configuration.byDefault.getSettingValue(cGroup, cValue); Object d = Configuration.byDefault.getSettingValue(dGroup, dValue); System.out.println(a); System.out.println(a.getClass()); System.out.println(b); System.out.println(b.getClass()); System.out.println(c); System.out.println(c.getClass()); System.out.println(d); System.out.println(d.getClass()); System.out.println(); System.out.println(); System.out.println("Showtime! Customized setting see below."); System.out.println(); System.out.println(); a = testConfig.getSettingValue(aGroup, aValue); b = testConfig.getSettingValue(bGroup, bValue); c = testConfig.getSettingValue(cGroup, cValue); d = testConfig.getSettingValue(dGroup, dValue); System.out.println(a); System.out.println(a.getClass()); System.out.println(b); System.out.println(b.getClass()); System.out.println(c); System.out.println(c.getClass()); System.out.println(d); System.out.println(d.getClass()); } }
      
      









この出力をコンソールに提供します



コンソールが表示したもの
 AAA class java.lang.String bbb class java.lang.String C class java.lang.String D... class java.lang.String Showtime! Customized setting see below. AAA class java.lang.String 1 class java.lang.Integer true class java.lang.Boolean D... class java.lang.String
      
      









したがって、デフォルトのデータが示されている一般的な設定と、このデータを部分的に重複または改良するこのような構成のセットがあると想定されます。 さらに、そのようなカスタムでデータが指定されていない場合、一般的な情報が使用されます。



このようなメカニズムを使用して、ブラウザーとモバイルアプリケーションを起動すると思います。 しかし、原則として、その柔軟性と拡張性により、幅広いアプリケーションを見つけることもできます。



以上で私のレビューは終わりです。 他にも面白いことがあります。 たぶん、私はそれらについて別の記事またはこれに関するコメントで話します。



2.どのように発展したか(叙情的な余談)。







私のキャリアのほとんどで、主にTest Completeを使用して、デスクトップソフトウェアのテストを自動化しています。 面白くてつまらないものがたくさんありました。 しかし、私は疲れています。 いくつかの創造性に惹かれました。



後で私はSelenium Webdriverについて知りました(そして今誰が知らないのですか?)。 最初は実験だけでした。 その後、アイデアが現れ始めました。 しかし...私は蓄積された練習からそれらを取った。 たとえば、Page Objectや実装例などの概念は、Wow効果を引き起こしませんでした。 デスクトップアプリケーションでも同様のことが必要でした。



上記の章で説明した実験は中止され、数か月後に再開されました。



次に、Appiumについて学びました。 私はたまたまこのプロジェクトに参加しました! 参加は自発的に始まりました-バグの報告から、私にとって問題と思われるものまで。 後にjava用のクライアントライブラリjava-clientが登場しました。 ここでの貢献はより深刻です。 PageFactoryを操作するための機能を実装し、ライブラリの再設計を支援しました。その結果、 AndroidDriverIOSDriver 、およびFirefox OSとWindows Mobileのサポートを追加する柔軟性がもたらされました 。 これが世界中の他の多くの人々を助けることを願っています。



3.結論。



コメントでお伝えできることを嬉しく思います。



私はこの実験を、Maven Centralビルドが利用可能であると言って恥ずかしくないような状態にしました。 とりあえず、それらを使って遊ぶか、簡単なテストケースを自動化することをお勧めします。



誰かがバグを見つけた場合-それはクールです! ここに説明してください 。 そしてコメントでは、批判やアイデアを読むのは素晴らしいことです。誰かがそれを賞賛するなら、それも良いことです。



私は説明されたものにこだわる必要はありません。 宴会を続けるというアイデアがあります-JUnit、TestNG、およびJbehaveのプラグインを実装することです。 たとえば、Eclipse IDE用のプラグインを作成できますが、これまでのところその機能はほとんど想像できません。 さらに、空のC#プロジェクトがまだあります。 しかし! 基本的な機能が必要な場合、これはすべて理にかなっています。 リクエストをプルするのはいつも嬉しいです!



じゃあね!










All Articles