レスポンシブデザむンを䜿甚したニュヌスサむトのレむアりトのテスト

EastBanc Technologies QA郚門がこれたでに盎面した最も泚目すべき課題の1぀は、サむトwww.washingtonpost.comの自動テストシステムの䜜成です。 これは、情報およびニュヌスポヌタルの圢匏で実装される電子新聞です。



自動テストシステムを䜜成する必芁がある䞻な理由は、アプリケヌションが新しいCMSいわゆるPageBuilderに切り替えるこずを蚈画しおいたためです。 この皮の移行では、さたざたなペヌゞで新しいCMSを通じお公開されたコンテンツが適切に芋えるように、ミスをしないこずが非垞に重芁です。



すべおのペヌゞがテストに準拠しおいるかどうかを確認する䜜業はありたせん。 私たちのタスクは、PageBuilderのバグを特定し、焌きたおのPageBuilderによっお䜜成されたペヌゞのレむアりトの信頌性を確認し、特定のペヌゞをペヌゞ衚瀺の朜圚的な問題に぀ながる可胜性のあるコンテンツで埋めるずいうニュアンスにWashingtonpost゚ディタヌの泚意を匕き付けるこずです。

テストシステムの䜜成は掻発に開発されおいたすが、私たちの意芋では、いく぀かの興味深い点がすでに䞀般に公開されおいたす。



これを行う前に、プロゞェクトの1぀の機胜に泚意する必芁がありたす。すべおのテストは「倖郚」で行われたす。 ぀たり 私たちは、他のナヌザヌず同様に、テスト甚に戊闘バヌゞョンのサむトを䜿甚したす。



レむアりトテストツヌルの遞択



むンタヌネットを探玢した埌、次のアプロヌチずツヌルに決めたした。 ペヌゞフレヌムをテストするために、埌でtestNGず統合したGalenフレヌムワヌクを採甚したした。



圓然、ペヌゞフレヌムのガレンテストに合栌しおも、レむアりトの有効性を意味するわけではありたせん。 ブロックの堎所に加えお、ブロック内のさたざたな芁玠の衚瀺も確認する必芁がありたす。 スクリヌンショットを比范しお、ブロックの内郚コンテンツをテストするこずにしたした。

さたざたなロゎ、ボタン、特定のディスプレむを備えた䞀郚のブロックは、スクリヌンショットテストに翻匄されたす。Galenが到達できず、機胜テストで怜蚌するこずが困難/䞍可胜であるすべおです。



Azure-Galenによっおテストされ、緑色であふれおいる-スクリヌンショットテスト



ご泚意 党䜓像

非衚瀺のテキスト








ガレンずスクリヌンショットのテストは、いく぀かの機胜テストを正垞に眮き換えるこずができ、同時に芖芚化、速床、そしお䞡方で勝利するこずができたす。 特定のケヌスのテスト方法の遞択は、パフォヌマンス基準、サポヌトの容易さ、テスト範囲の完党性、および可芖性に基づいお、ペヌゞの皮類ごずにテストケヌスをたずめお議論するこずにより行われたす。



たずえば、最初に機胜テストを蚘述した怜蚌甚ブロックには、Most ReadブロックずInformation Blockの2぀がありたす。 今床は、スクリヌンショットで最初をチェックし、ガレンテストで2番目をチェックしたす。



MostReadブロック、スクリヌンショットテストによる怜蚌





機胜テストに関しおコヌドの行がはるかに小さくなり、テストカバレッゞの完党性が向䞊し、ペヌゞ䞊のこのブロックの倖芳を倉曎するずきにテストを曎新するのにそれほど時間はかかりたせん。



このブロックのテストは、スクリヌンショット方匏の章で怜蚎されおいたす。



WaPo情報ブロック





Galenはこのブロックのテキストずリンクの察応を問題なくチェックしたす。リンク自䜓はロケヌタヌで指定され、テキストず内郚ガレンチェックずの察応は確認されたす。 機胜テストに関しおは、テスト範囲の完党性は倉曎されおいたせんが、テストが単䞀のテストの䞀郚ずしお実行されるずいう事実により、時間を倧幅に節玄できたす。



ガレノステストコヌド 。



圓瀟の自動テストシステムは、Java、Maven、TestNG、 Selenium WebDriver 、Selenium Grid、 Galen Frameworkを䜿甚しおいたす。



スクリヌンショットベヌスのテストを䜜成する際に、 ImageMagickナヌティリティのクロスプラットフォヌムセットが積極的に圹立ちたす。



PageObjectパタヌンずYandex- HTML Elementsのフレヌムワヌクを䜿甚しおJavaでテストコヌドを蚘述しおいるこずにすぐに泚目したす 。 テストを実行するには、mavenずtestNGが䜿甚されたす。



テストの立ち䞊げを容易にするため、テストの立ち䞊げの履歎を衚瀺し、高床な資栌を持぀専門家が関䞎するこずなくレポヌトを衚瀺するために、別のアプリケヌション-ダッシュボヌドを開発しおいたす。



珟圚、テストプロセス党䜓を適切に敎理する方法に぀いおはただ研究段階にあり、すべおのアプロヌチが完党にマスタヌされ、研究されおいるわけではないこずを匷調しおおくず圹立ちたす。



Galen Frameworkを䜿甚したテスト



Galen Frameworkには倚くの吊定できない利点がありたす。レスポンシブデザむンのための広範なテスト機胜を備えた、柔軟で䜿いやすいツヌルです。 さらに、十分に文曞化されおおり、珟圚積極的に開発䞭です。



Galen Frameworkは、すでに蚘事の 1぀で十分詳现に説明されおいたす。 Galenでの䜜業の原則を簡単に説明するず、次のようになりたす。特別に文曞化された盎感的な構文を䜿甚しおペヌゞ仕様いわゆるspecファむルを蚘述したす。 仕様ファむルには、ペヌゞ芁玠の盞察的な䜍眮、サむズ、むンデント、ネスト、およびペヌゞレむアりトが準拠すべきその他のパラメヌタヌず条件が蚘述されおおり、芁玠内のテキストの察応を確認するこずもできたす。 そしお、これらのチェックはすべお、指定したタグに応じお適甚されたす。



specファむルのタグは次のように指定できたす。











Galenはすべおのチェックを実行しおから、htmlファむルの圢匏で芖芚的なレポヌトを生成したす。 レポヌトには、このテストで倱敗した特定のチェックが瀺され、倱敗した各チェックに぀いお、特定のテストに合栌しなかった芁玠が匷調衚瀺されるテスト枈みペヌゞの完党なスクリヌンショットを芋るこずができたす。

たずえば、隣接する芁玠間の距離のテストに倱敗するず、レポヌトでは次のようになりたす。







赀で匷調衚瀺されたチェックをクリックするず、チェックされたペヌゞ党䜓のスクリヌンショットが衚瀺され、そのような芁玠が匷調衚瀺されたす。







Galen Frameworkは、次のパラメヌタヌを入力ずしお受け入れたす。





ご芧のずおり、Galenに提䟛されるパラメヌタヌを倉曎するこずで、サむトのフレヌムワヌクのほが完党なテストカバレッゞを達成できたす。



サむトワむダフレヌムテストツヌルを決定したら、次のタスクは、Galenテストでペヌゞの最倧カバレッゞを提䟛できるスキヌムを遞択するこずでした。



同じタむプのペヌゞのサブセットからテストペヌゞを遞択する


テストが同じタむプのペヌゞの倚くをチェックするように蚭蚈されおいる堎合、レむアりトをテストするために遞択するペヌゞはどれですか



特に気にするこずなく、テストスむヌトを実行するたびにサブセットからランダムペヌゞを遞択するこずにしたした぀たり、レシピペヌゞのサブセットをテストするために、レシピの1぀を遞択し、そのURLをすべおのレむアりトテストに枡したす。 したがっお、タスクのすべおのペヌゞをチェックする䟡倀がないため、ランダムペヌゞを遞択するオプションが最適であるように芋えたした。 チェックされたペヌゞのサブセットのランダムペヌゞのURLは、自動サむトテストシステム内のすべおのテストに共通の方法でGalenに送信されたす組版テストを陀き、機胜テストずスクリヌンショットテストもありたす。



たずえば、同じタむプのペヌゞを衚瀺するための2぀のオプションがありたす-レシピのペヌゞで、そのうちの1぀に゚ラヌが含たれおいたす







この䟋は、ペヌゞの右偎の列に配眮する必芁がある「Most Read」ブロックが、メむンペヌゞの巊偎ではなく右偎にあるこずを瀺しおいたす。 この皮の問題がないこずを確認するには、倚数のペヌゞを確認し、倚くの芁因を考慮する必芁がありたす。



どの暩限でテストを実行したすか


最初に、最も䞀般的なデバむスを遞択し、その解像床を䜿甚しおテストを実行するずいうアむデアが生たれたした。 しかし、惑星の加速された動員の明確に远跡された傟向は、私たちがこの分野の無条件の指導者を遞抜するそしおさらに予枬するこずを蚱したせん。 Webアプリケヌションを衚瀺できるデバむスはたくさんありたすが、最近ではそのようなデバむスに察する暩限の統䞀は絶察に流行しおいたせん。 突然のクリヌピングは、任意の有効な解像床で正しく衚瀺するためにアダプティブデザむンがアダプティブであるず考え、私たちの心を救い、この分野のさらなる研究を劚げたした。 決定が䞋されたした。すべおの有効な解像床でレむアりトをテストしおいたす。



有効なアクセス蚱可には、最小ビュヌポヌト幅= 241ピクセルブラりザヌが枛少するこずはありたせんから最倧ビュヌポヌト幅= 1920ピクセル䞊限は単玔な自発的な努力たでのすべおのアクセス蚱可が割り圓おられたした。 自動テストのためのビュヌポヌトの高さが決定パラメヌタであるペヌゞはただないため、これたでのずころ高さに泚意を払いたせん。



すべおの解像床でレむアりトをテストする方法は



たず、有効な暩限の範囲党䜓が異なるレむアりトの範囲に分割されたした。 レむアりト自䜓は「ゎム」ですが、ブロックの配眮が異なるため、区別するこずができたす。 レむアりトの境界を決定するこずは難しくありたせん。ブラりザの隅でドラッグし、ペヌゞブロックがどの境界点で倉化するかを調べたす盞察的な䜍眮、数、および/たたは動䜜。 簡略化するために、ビュヌポヌトの幅のみを考慮したす。 次の衚が刀明したした。



デスクトップ最倧1920ピクセル、最小1018ピクセル。

ラップトップ最倧1017px、最小769px。

タブレット最倧768ピクセル、最小481ピクセル。

モバむル最倧480ピクセル、最小361ピクセル。

SMALL_MOBILE最倧360ピクセル、最小280ピクセル。



ちなみに、このような解像床のデバむスでWashington Postを衚瀺するナヌザヌの数は悲惚なほど少ないため、SMALL_MOBILEレむアりトをテストしないこずにしたした掚枬的な結論であり、さらにテストを远加しおも問題ありたせん。 異なる組版で4぀の範囲をテストするために残りたす。



以䞋は、デスクトップのアクセス蚱可に぀いおGalenテストを実行するコヌドです。

非衚瀺のテキスト
@Test(groups = { "Galen" }) @WebTest(value = "Verify that layout of Article page is not broken on desktop screen resolution.", bugs = {"#5599", "#5601", "#5600"}) public void testArticlepageLayoutOnDesktop() throws Exception { GalenActionsBuilder builder = new GalenActionsBuilder() //advertisement frames become visible only if advertisement placeholder is visible .waitForVisible(5, ".pb-f-ad-leaderboard > div> div > div > iframe") .scrollToElement(".pb-f-ad-flex") .waitForVisible(5, ".pb-f-ad-flex > div > div > iframe") .scrollToElement(".pb-f-ad-flex-2") .waitForVisible(5, ".pb-f-ad-flex-2 > div > div > iframe") .scrollToElement(".pb-f-ad-flex-3") .waitForVisible(5, ".pb-f-ad-flex-3 > div > div > iframe") .injectJavascript("/js/scroll_to_top.js") .waitSeconds(2) .check("/article.spec", Arrays.asList("all", "desktop")); invokeGalenActions(ArticlePage.getRandomArticlePage(), builder.build(), getRandomResolution(DESKTOP)); }
      
      





invokeGalenActionsメ゜ッドは、このフレヌムワヌクによっお消化された圢匏のすべおの前提条件をGalenに提䟛したす。



 protected void invokeGalenActions(String url, List<GalenPageAction> actions, Dimension... sizes) throws Exception { run(url, actions, recalculateSizes(sizes)); }
      
      







GalenActionBuilderを䜿甚するず、䞡方のネむティブガレンの前提条件.waitForVisible5、 ".pb-f-ad-leaderboard> div> div> div> iframe"ず関連.scrollToElement "。Pb- f-ad-flex "



 public class GalenActionsBuilder { private boolean built; private final List<GalenPageAction> actions = new ArrayList<>(); public GalenActionsBuilder waitFor(Integer seconds, GalenPageActionWait.UntilType type, Locator locator) { checkUsed(); GalenPageActionWait.Until u = new GalenPageActionWait.Until(type, locator); GalenPageActionWait a = new GalenPageActionWait(); a.setTimeout(seconds * 1000); a.setUntilElements(Lists.newArrayList(u)); a.setOriginalCommand("wait " + seconds + "s until " + type.toString() + " " + locator.getLocatorValue()); actions.add(a); return this; } public GalenActionsBuilder waitSeconds(Integer seconds) { checkUsed(); GalenPageActionWait a = new GalenPageActionWait(); a.setTimeout(seconds * 1000); a.setOriginalCommand("wait " + seconds + "s"); actions.add(a); return this; } public GalenActionsBuilder waitForExist(Integer seconds, String cssSelector) { return waitFor(seconds, GalenPageActionWait.UntilType.EXIST, Locator.css(cssSelector)); } public GalenActionsBuilder waitForVisible(Integer seconds, String cssSelector) { return waitFor(seconds, GalenPageActionWait.UntilType.VISIBLE, Locator.css(cssSelector)); } public GalenActionsBuilder waitForHidden(Integer seconds, String cssSelector) { return waitFor(seconds, GalenPageActionWait.UntilType.HIDDEN, Locator.css(cssSelector)); } public GalenActionsBuilder waitForGone(Integer seconds, String cssSelector) { return waitFor(seconds, GalenPageActionWait.UntilType.GONE, Locator.css(cssSelector)); } public GalenActionsBuilder waitForExist(Integer seconds, Locator locator) { return waitFor(seconds, GalenPageActionWait.UntilType.EXIST, locator); } public GalenActionsBuilder waitForVisible(Integer seconds, Locator locator) { return waitFor(seconds, GalenPageActionWait.UntilType.VISIBLE, locator); } public GalenActionsBuilder waitForHidden(Integer seconds, Locator locator) { return waitFor(seconds, GalenPageActionWait.UntilType.HIDDEN, locator); } public GalenActionsBuilder waitForGone(Integer seconds, Locator locator) { return waitFor(seconds, GalenPageActionWait.UntilType.GONE, locator); } public GalenActionsBuilder withCookies(String... cookies) { checkUsed(); GalenPageActionCookie a = new GalenPageActionCookie() .withCookies(cookies); a.setOriginalCommand("cookie " + Joiner.on("; ").join(cookies)); actions.add(a); return this; } public GalenActionsBuilder injectJavascript(String javascriptFilePath) { checkUsed(); GalenPageActionInjectJavascript a = new GalenPageActionInjectJavascript(javascriptFilePath); a.setOriginalCommand("inject " + javascriptFilePath); actions.add(a); return this; } public GalenActionsBuilder runJavascript(String javascriptFilePath) { checkUsed(); GalenPageActionRunJavascript a = new GalenPageActionRunJavascript(javascriptFilePath); actions.add(a); return this; } public GalenActionsBuilder runJavascript(String javascriptFilePath, String jsonArgs) { checkUsed(); GalenPageActionRunJavascript a = new GalenPageActionRunJavascript(javascriptFilePath) .withJsonArguments(jsonArgs); actions.add(a); return this; } public GalenActionsBuilder check(String specFile, List<String> tags) { checkUsed(); GalenPageActionCheck a = new GalenPageActionCheck() .withSpecs(Arrays.asList(specFile)) .withIncludedTags(tags); actions.add(a); return this; } public GalenActionsBuilder resize(int width, int height) { checkUsed(); GalenPageActionResize a = new GalenPageActionResize(width, height); a.setOriginalCommand("resize " + GalenUtils.formatScreenSize(new Dimension(width, height))); actions.add(a); return this; } public GalenActionsBuilder open(String url) { checkUsed(); GalenPageActionOpen a = new GalenPageActionOpen(url); a.setOriginalCommand("open " + url); actions.add(a); return this; } private void checkUsed() { if (built) throw new IllegalStateException("Incorrect builder usage error. build() method has been already called"); } public List<GalenPageAction> build() { built = true; return actions; } public GalenActionsBuilder scrollToElement(String locator) { String content = String.format("jQuery(\"%s\")[0].scrollIntoView(true);", locator); Properties properties = new Properties(); try (InputStream is = getClass().getResourceAsStream("/test.properties")){ properties.load(is); } catch (Exception e) { throw new RuntimeException("I/O Exception during loading configuration", e); } String workDirPath = properties.getProperty("work_dir"); String tempDirPath = workDirPath + "\\temp"; String auxJsFile = String.format("%s\\%s.js", tempDirPath, locator.hashCode()); File tempDir = new File(tempDirPath); tempDir.mkdirs(); try { PrintWriter writer = new PrintWriter(auxJsFile, "UTF-8"); writer.println(content); writer.close(); } catch (Exception e) { throw new RuntimeException("Exception during creating file", e); } injectJavascript(auxJsFile); return this; } }
      
      









各テストの開始時に、Galenには、指定されたレむアりトの範囲からランダムな蚱可が䞎えられたすgetRandomResolutionDESKTOP



 protected Dimension getRandomResolution(Dimension[] d) { return getRandomDimensionBetween(d[0], d[1]); } private Dimension getRandomDimensionBetween(Dimension d1, Dimension d2) { double k = Math.random(); int width = (int) (k * (Math.abs(d1.getWidth() - d2.getWidth()) + 1) + Math.min(d1.getWidth(), d2.getWidth())); int height = (int) (k * (Math.abs(d1.getHeight() - d2.getHeight()) + 1) + Math.min(d1.getHeight(), d2.getHeight())); return new Dimension(width, height); }
      
      







そしお実際、蚱可の範囲は次の圢匏で蚭定されたす。



 public static final Dimension[] DESKTOP = {new Dimension(1920, 1080), new Dimension(1018, 1080)};
      
      







したがっお、有効な範囲から解像床をランダムに遞択し、同じタむプのペヌゞのサブセットからテスト枈みのペヌゞを遞択するこずにより、確率的なプロセスになりたす。 起動すればするほど、さたざたなバグが芋぀かりたす。 テストに1回合栌するず、この特定の解像床のこの特定のペヌゞが有効であるずしか蚀えたせん。 しかし、500回の実行が成功した埌、レむアりトの倧郚分は実行可胜であるず䞻匵できたす。 「500件の成功」が投機的な評䟡であるずいう予玄をすぐに行いたす。ここでは、コンテンツず同等のペヌゞ数を確認する必芁がありたす。



ランダム解像床で実行するずすぐに成果が䞊がり、固定解像床でテストを実行したずきに芋逃しおいたず思われる興味深いバグがすぐに明らかになりたした。



レシピペヌゞをテストする䟋で、このアプロヌチがどのように圹立぀かを怜蚎しおください。



レシピペヌゞのワむダフレヌムテストは、768px〜1017pxの解像床範囲ビュヌポヌト幅で実行されたす。 たずえば、次のペヌゞをご芧ください www.washingtonpost.com/pb/recipes/maple-banana-frozen-yogurt/14143



Laptop layout'a1017pxおよび768pxのベンチマヌクテストでぱラヌは発生したせんでした。



ただし、ランダムな解像床でテストを実行し始めた埌、玄半分のケヌスでテストが倱敗し、スクリヌンショットでは、右の列のブロックがメむンコンテンツの䞋に忍び蟌んでいるこずが瀺されたした。



正しい芋解



ご泚意 党䜓像

非衚瀺のテキスト








壊れたレむアりト



ご泚意 党䜓像

非衚瀺のテキスト








スクリヌンショットベヌスのテスト方法



蚘事に觊発されお、スクリヌンショットベヌスのテスト方法を䜿甚するこずにしたした。 ずころで、レむアりトをテストするために、最初はこのメ゜ッドに䟝存しおいたした。 ぀たり ペヌゞのフルサむズのスクリヌンショットを事前に準備されたモデルず比范し、朜圚的に倉化するすべおの芁玠をスタブに眮き換えるずいう考えがありたした事前に遞択された任意の画像がスタブずしお取埗されたす。 これらの芁玠には、写真、フラッシュ広告、テキストが含たれたす。 このアむデアは䞻に、ペヌゞに動的にロヌドされる倚くのブロックが含たれおいたため、スクリヌンショットの物理的寞法ずブロックの堎所がテストの実行から実行に倉曎されたために倱敗したした。 たた、Chromeはフルサむズのスクリヌンショットを撮る機胜をしばらく倱い、これも倚くの問題を匕き起こしたした。



スクリヌンショットベヌスのテストは、衚瀺が重芁なペヌゞ䞊の個々の芁玠ずブロックをチェックするようになりたした。機胜テストたたはガレンテストを䜿甚したチェックは困難たたは䞍可胜です。



䟋



washingtonpost.comのメむンペヌゞ巊のMostReadブロックず、このブロックのスクリヌンショットを比范するモデル右です。







テストコヌドは次のようになりたす。



 @Test(groups = { "ScreenshotBased" }) @WebTest("Verifies that 'Post Most' block is displayed properly") public void testMakeupForPostMost() { HomePage page = new HomePage().open(); page.preparePostMostForScreenshot(); screenshotHelper.shootAndVerify(page, page.thePostMost, "_thePostMost"); }
      
      







スクリヌンショットの保存には、次のディレクトリ構造が䜿甚されたす。/models/HomePage/firefox/HomePage_thePostMost.png



ここからわかるように、さたざたなブラりザヌに぀いお、必芁なブロックのモデルスクリヌンショットが取埗されたす。



shootAndVerifyメ゜ッドは、送信されたペヌゞのクラスずテストが実行されおいるブラりザヌの名前によっおモデルぞのパスを怜玢したす。



先に芋おみたしょう-それは非垞にうたく機胜したす、そしお、すべおがただ完党にデバッグされおいないずいう譊告でプロセスのいく぀かの詳现を説明したす。



刀明したように、必芁なブロックの写真は、次のような倚くの芁因に䟝存する可胜性がありたす。





最初の問題は、撮圱されたスクリヌンショットのサむズがOSずブラりザの蚭定によっお異なるこずでした。 ブロックのサむズ、および結果ずしおスクリヌンショットを同じにするには、䞀定のサむズでブラりザヌを実行する必芁がありたす。 適切なWebドラむバヌメ゜ッドを䜿甚しお、ブラりザヌりィンドりのサむズを倉曎できたすdriver.manage。Window。SetSizerequiredSize。 ただし、この方法で、必芁な衚瀺領域ビュヌポヌトのサむズではなく、りィンドりのサむズを蚭定したす。 ちなみに、垂盎スクロヌルバヌはビュヌポヌトのサむズにも圱響し、その倪さもりィンドりのテヌマに䟝存するため、これを考慮する必芁がありたす。 問題の解決策は、指定された寞法にビュヌポヌトのサむズを調敎するキャリブレヌション方法でした。 最初のテストを開始した埌、りィンドりサむズの幅ずビュヌポヌトの幅の差は特別なパラメヌタヌに保存され、以降の起動時に再利甚されたす。



私たちが遭遇した2番目の問題は、アンチ゚むリアシングオプションによるブラりザヌでのフォントの異なる衚瀺でした。 次のようなさたざたなブラりザ蚭定をむンストヌルしお、問題を解決しようずしたした。



layers.acceleration.disabled

gfx.font_rendering.cleartype_params.rendering_mode

gfx.direct2d.disabled



しかし、残念ながら、これは圹に立ちたせんでした。



さらに、スクリヌンショットをImageMagickず比范するために、fuzzなどのパラメヌタヌを䜿甚しお、スクリヌンショット間の可胜な最倧差を蚭定したす。



このパラメヌタヌを詊しお、この問題を解決しようずしたした。 倚数のテキストが存圚するずいう事実のために、さたざたなピクセルの数が非垞に倧きいため、小さなファズ係数は問題を解決したせんでした。たた、係数が倧きいず、ブロック内のいく぀かの芁玠がなくおもテストの合栌に圱響せず、バグを芋逃す可胜性がありたした。



解決策は、テストが実行されたすべおの仮想マシンでさたざたなブラりザヌのすべおの蚭定を耇補し、オペレヌティングシステム自䜓の蚭定を耇補するこずでした。



たずえば、画像の1぀がロヌドされなかった゜ヌシャルボタンのブロックをチェックするテスト。



レポヌトでは次のリンクを䜿甚できたす。



モデル画像





テストブロックのスクリヌンショット





これらの2぀の画像を比范した結果





CommandExceptionは、比范された画像が251px異なるこずを瀺しおいたす。





スクリヌンショットのサむズが䞀臎しない状況もありたす。 この堎合、次のレポヌトを受け取りたす。







未知の理由で、テストブロック内の芁玠がわずかに偏っおいる堎合がありたす。 このような堎合、1぀のモデルず比范するのではなく、マスクに適したモデルのグルヌプず比范したす。 HomePage_thePostMost.png、HomePage_thePostMost1.pngずいう名前のthePostMostブロックの耇数のモデルを䜜成でき、すべおのモデルが有効であるず芋なしたす。 幞いなこずに、そのようなオプションの数は有限であり、通垞は2以䞋です。



技術的偎面



前述のように、テスト、Java、Maven、TestNG、Selenium、Galen Frameworkの䜜成ず実行にはテクノロゞヌスタックが䜿甚されたす。 さらに、テスト結果はグラファむトに送信されたす。 テストは、Jenkins CISを䜿甚しお盎接実行されたす。 このようなセットが遞択された理由に぀いおは詳しく説明したせん。 これがすべお盞互接続されおいる方法を簡単に説明したす。



Selenium Gridは、グリッドノヌドが実行されおいるWindows 7を備えた4぀の仮想マシンず、ハブが実行されおいるLinuxマシンにロヌカルで展開されたす。 各ノヌドで䜿甚可胜なFirefoxおよびChromeブラりザの3぀のむンスタンスがありたす。 さらに、ゞェンキンスずグラファむトもLinuxマシンに展開されたす。 Galenテストは、TestNGずの統合を通じお䞀般的なテスト実行で実行されたす。 これを行うために、jav Galen APIを䜿甚できる適切なクラスが䜜成されたした。 TestNGずガレンの盞互䜜甚を実装する際に、ガレン開発者ずの盞互䜜甚によりすぐに解決されるいく぀かの問題がありたした。 方鉛鉱開発者自身が喜んで協力し、定期的にこのツヌルのアップデヌトをリリヌスしたす。これにより、機胜が拡匵され、さらに䟿利になりたす。 圌自身は、ガレンずTestNGの統合に関するドキュメントを曞く予定です。



機胜、ガレン、およびスクリヌンショットベヌスのテストは、Testアノテヌションに割り圓おられた適切なグルヌプパラメヌタヌを䜿甚しお分離され、個別に起動される可胜性がありたす。



結論



スクリヌンショットの比范ずGalen Frameworkを䜿甚したテストの䞡方の方法は、ペヌゞレむアりトのテストに適甚できたす。 それらは互いにうたく補完し合う。 スクリヌンショットを比范する方法は、゜ヌシャルネットワヌクの共有パネルやヘッダヌのメむンメニュヌなど、単䞀の芁玠たたはブロックの衚瀺をテストする必芁がある堎合により適しおいたす。 ブロックには、その䞭に倚くのアむコンを含めるこずができたす。これらのアむコンは、他のアむコンや芁玠の䞭に配眮したり、盞察的な䜍眮を蚭定したりできたす。



Galenを䜿甚しおこれらすべおの小さな瞬間を蚘述するのはかなり時間がかかりたすが、各ブラりザヌの1぀のスクリヌンショットはこの問題を解決し、スクリヌンショットの比范では、仕様を説明するずきに䜕かを芋逃す可胜性があるオプションを陀倖したす。 次に、Galenはブロックの盞察的な配眮に察凊し、ヘッダヌずその䞭の固定テキストをチェックしたす。 たずえば、情報ポヌタルなど、機胜ロゞックが読み蟌たれおいない同じタむプのテンプレヌトペヌゞでレむアりトをテストする必芁がある堎合、このケヌスのように、サむトのほずんどすべおのペヌゞに蚱可なくアクセスできる堎合、たたは他のナヌザヌアクションを実行する堎合に圹立ちたす。 さらに、Galenは適応型アプリケヌションレむアりトのクロスブラりザヌテストをうたく解決したす。



All Articles