SeleniumWebDriver如何自動化可視化驗(yàn)證圖表和繪圖(如折線圖,餅圖因俐,柱狀圖)

Chart

文章首發(fā)于微信公眾號軟測小生

前言:
圖表(Chart)的自動驗(yàn)證是測試自動化的最大挑戰(zhàn)之一拇惋, 而在我們的應(yīng)用程序中,我們有大量的圖表抹剩,接下來將展示我是如何自動化Chart撑帖,或許給你一些新的想法。

Ocular

我將使用Ocular-圖像驗(yàn)證庫! 事實(shí)上澳眷,我創(chuàng)建這個Ocular 庫就是為了這個目的胡嘿。

示例應(yīng)用:
為了更好地解釋,我將創(chuàng)建兩個簡單的HTML文件境蔼,如下所示(我從這個站點(diǎn)獲取HTML) &每個HTML文件包含3個圖表灶平。

在這里插入圖片描述

這里我們假設(shè)右邊的圖表和左邊的完全一樣伺通。除了收入圖表的1月份數(shù)據(jù)不一樣之外箍土,右邊的圖表幾乎是一樣的。

我的期望是——作為自動化測試的一部分罐监,應(yīng)該報告這種差異吴藻,測試應(yīng)該失敗!

HTML源代碼看起來是這樣的:


HTML源碼

現(xiàn)在是時候?yàn)樯厦娴腍TML文件設(shè)計Page對象了:

Page Object:

package com.chart.demo;

import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;
import com.testautomationguru.ocular.Ocular;
import com.testautomationguru.ocular.comparator.OcularResult;

public class SampleChartPage {

    private WebDriver driver;
    private Map<String, String> map;

    @FindBy(id = "buyers")
    private WebElement buyersChart;

    @FindBy(id = "countries")
    private WebElement countriesChart;

    @FindBy(id = "income") WebElement incomeChart;
//    private WebElement incomeChart;

    public SampleChartPage(WebDriver driver) {
        this.driver = driver;
        PageFactory.initElements(driver, this);

        // 頁面對象應(yīng)該包含準(zhǔn)圖像的路徑
        // 這些圖像不需要存在
        // Ocular如果沒有找到,會創(chuàng)建這些圖像
        map = new HashMap<String, String>();
        map.put("buyers", "buyers.png");
        map.put("countries", "countries.png");
        map.put("income", "income.png");
    }

    public boolean verifyBuyersChart() {
        return this.verifyChart(map.get("buyers"), buyersChart);
    }

    public boolean verifyCountriesChart() {
        return this.verifyChart(map.get("countries"), countriesChart);
    }

    public boolean verifyIncomeChart() {
        return this.verifyChart(map.get("income"), incomeChart);
    }

    // 常用的方法來比較基準(zhǔn)圖像與實(shí)際的某個頁面/特定元素
    private boolean verifyChart(String fileName, WebElement element) {

        //Path path = Paths.get(fileName); //只為這個方法實(shí)用--baselineTest()
        Path path = Paths.get(fileName).toAbsolutePath();//為這兩個方法使用visaul_test_without_any_change()和visaul_test_after_change() 
        System.out.println(path);
        OcularResult result = Ocular.snapshot().from(path)       //(1)
                                    .sample().using(driver).element(element)      //(2)
                                    .compare(); //(3)
        int similarity = result.getSimilarity();
        System.out.println("similarity="+similarity);
        
        return result.isEqualsImages();
    }
}

我假設(shè)以上page對象是不言自明的弓柱。我在項(xiàng)目中創(chuàng)建了這樣的文件夾沟堡。

  • snap文件夾應(yīng)該包含所有的基準(zhǔn)圖像
  • result將包含比較結(jié)果


    文件夾

    最初這些文件夾可以是空的。因?yàn)槲覀儾粫心?個圖表網(wǎng)頁元素的圖像(在第一次運(yùn)行時矢空,Ocular將在snap文件夾下創(chuàng)建這些圖像)航罗。
    接下來我們開始創(chuàng)建測試用例:

TestNG Test:

在這個testNG測試集中,我有3個測試:

  • baseline_test——此測試的目的是首先生成基準(zhǔn)圖像屁药,當(dāng)您第一次運(yùn)行測試時粥血,Ocular將創(chuàng)建基準(zhǔn)圖像。這樣酿箭,您就可以將它用于后續(xù)的任何驗(yàn)證复亏。這個測試總會PASS
  • visual_test_without_any_change ——這里缭嫡,我將調(diào)用相同的HTML文件缔御。因此,Ocular會將圖表與之前測試方法(baseline_test)中創(chuàng)建的基準(zhǔn)圖像進(jìn)行比較妇蛀。這個測試將PASS耕突,因?yàn)槭褂孟嗤臄?shù)據(jù)啟動了相同的HTML笤成,所以圖表將與預(yù)期一樣。
  • visual_test_after_change ——在這個測試中眷茁,我將啟動另一個HTML疹启,其中收入(income)圖表數(shù)據(jù)略有變化。因此蔼卡,Ocular將驗(yàn)證和報告圖片的差異喊崖。
    一旦我運(yùn)行baseline_test方法, snap文件夾將包含我們需要的所有圖像!
    image
package com.chart.demo;
import java.nio.file.Paths;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.testng.Assert;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.BeforeSuite;
import org.testng.annotations.Test;
import com.testautomationguru.ocular.Ocular;

public class OcularDemo {
    private WebDriver driver;
    private SampleChartPage page;

    @BeforeSuite
    public void ocularConfig() {
        //更新Ocular配置
        // 設(shè)置基準(zhǔn)圖像的路徑——這個文件夾應(yīng)該存在
        // 設(shè)置比較后返回結(jié)果的路徑 - 這個文件夾應(yīng)該存在
        Ocular.config()
               .snapshotPath(Paths.get(".", "resources/snap"))
               .resultPath(Paths.get(".", "resources/result"));        
    }

    @BeforeMethod
    public void beforeMethod() {
        driver = new ChromeDriver();
        driver.manage().window().maximize();
    }

    @AfterMethod
    public void afterMethod() {
        driver.quit();
    }

    // 在這個測試的時候,snap文件是空的. ocular沒有發(fā)現(xiàn)任何基準(zhǔn)圖像. 
    // 所以O(shè)cular創(chuàng)建了基準(zhǔn)圖像并且對比結(jié)果總是返回True
    @Test
    public void baselineTest() throws InterruptedException {
        driver.get("file:///" + Paths.get("Chart.jsdemo0.html").toAbsolutePath());
        Thread.sleep(5000);
        page = new SampleChartPage(driver);

        Assert.assertTrue(page.verifyBuyersChart());
        Assert.assertTrue(page.verifyCountriesChart());
        Assert.assertTrue(page.verifyIncomeChart());
    }

    // 在這個測試中,snap文件包含了基準(zhǔn)圖像.
    // 所以O(shè)cular對比了實(shí)際元素獲取的圖像并返回結(jié)果
    @Test/*(dependsOnMethods = "baselineTest")*/
    public void visaul_test_without_any_change() throws InterruptedException {
        driver.get("file:///" + Paths.get("Chart.jsdemo0.html").toAbsolutePath());

        page = new SampleChartPage(driver);

        Assert.assertTrue(page.verifyBuyersChart());
        Assert.assertTrue(page.verifyCountriesChart());
        Assert.assertTrue(page.verifyIncomeChart());
    }

    // snap文件夾下已經(jīng)包含了基準(zhǔn)圖像.
    // 所以O(shè)cular對比了實(shí)際元素獲取的圖像并返回結(jié)果
    // income圖標(biāo)的數(shù)據(jù)改變了 -所以他將失敗
    @Test/*(dependsOnMethods = "visaul_test_without_any_change")*/
    public void visaul_test_after_change() throws InterruptedException {
        driver.get("file:///" + Paths.get("Chart.jsdemo1.html").toAbsolutePath());
        Thread.sleep(5000);
        page = new SampleChartPage(driver);
        
        Assert.assertTrue(page.verifyBuyersChart());
        Assert.assertTrue(page.verifyCountriesChart());
        Assert.assertTrue(page.verifyIncomeChart());  //這里將會失敗雇逞,因?yàn)閿?shù)據(jù)改變了
    }
}

對于失敗的測試用例荤懂,差異被高亮顯示,如下所示!!


失敗的測試用例可視化

總結(jié):
大多數(shù)自動化套件通過讀取圖表數(shù)據(jù)來進(jìn)行比較塘砸,如果數(shù)據(jù)與預(yù)期相符节仿,則很難對圖表進(jìn)行實(shí)際驗(yàn)證。但是掉蔬,再看我們上面的例子廊宪,通過Ocular來驗(yàn)證圖表不再是一個大的挑戰(zhàn)! 如果我們通過基準(zhǔn)圖像位置和元素,Ocular比較高亮出差異是很容易的女轿。
這只是局部箭启,希望能夠幫到你,更多內(nèi)容請查看Ocular的源碼蛉迹。

Maven依賴

其中用到的Maven依賴如下:

<!-- https://mvnrepository.com/artifact/com.testautomationguru.ocular/ocular -->
<dependency>
    <groupId>com.testautomationguru.ocular</groupId>
    <artifactId>ocular</artifactId>
    <version>1.0.0.Alpha</version>
</dependency>

Demo HTML網(wǎng)頁獲取

其中該Demo所用到的HTML網(wǎng)頁傅寡,可以到CSDN下載,但是有點(diǎn)惡心要積分北救;
也可關(guān)注微信公眾號軟測小生回復(fù)“ChartDemo”獲取下載鏈接荐操。
下載后解壓使用說明如下圖:

項(xiàng)目文件

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市珍策,隨后出現(xiàn)的幾起案子托启,更是在濱河造成了極大的恐慌,老刑警劉巖攘宙,帶你破解...
    沈念sama閱讀 216,591評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件屯耸,死亡現(xiàn)場離奇詭異,居然都是意外死亡模聋,警方通過查閱死者的電腦和手機(jī)肩民,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,448評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來链方,“玉大人持痰,你說我怎么就攤上這事∷钍矗” “怎么了工窍?”我有些...
    開封第一講書人閱讀 162,823評論 0 353
  • 文/不壞的土叔 我叫張陵割卖,是天一觀的道長。 經(jīng)常有香客問我患雏,道長鹏溯,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,204評論 1 292
  • 正文 為了忘掉前任淹仑,我火速辦了婚禮丙挽,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘匀借。我一直安慰自己颜阐,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,228評論 6 388
  • 文/花漫 我一把揭開白布吓肋。 她就那樣靜靜地躺著凳怨,像睡著了一般。 火紅的嫁衣襯著肌膚如雪是鬼。 梳的紋絲不亂的頭發(fā)上肤舞,一...
    開封第一講書人閱讀 51,190評論 1 299
  • 那天,我揣著相機(jī)與錄音均蜜,去河邊找鬼李剖。 笑死,一個胖子當(dāng)著我的面吹牛兆龙,可吹牛的內(nèi)容都是我干的杖爽。 我是一名探鬼主播,決...
    沈念sama閱讀 40,078評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼紫皇,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了腋寨?” 一聲冷哼從身側(cè)響起聪铺,我...
    開封第一講書人閱讀 38,923評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎萄窜,沒想到半個月后铃剔,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,334評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡查刻,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,550評論 2 333
  • 正文 我和宋清朗相戀三年键兜,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片穗泵。...
    茶點(diǎn)故事閱讀 39,727評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡普气,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出佃延,到底是詐尸還是另有隱情现诀,我是刑警寧澤夷磕,帶...
    沈念sama閱讀 35,428評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站仔沿,受9級特大地震影響坐桩,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜封锉,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,022評論 3 326
  • 文/蒙蒙 一绵跷、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧成福,春花似錦抖坪、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,672評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至握侧,卻和暖如春蚯瞧,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背品擎。 一陣腳步聲響...
    開封第一講書人閱讀 32,826評論 1 269
  • 我被黑心中介騙來泰國打工埋合, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人萄传。 一個月前我還...
    沈念sama閱讀 47,734評論 2 368
  • 正文 我出身青樓甚颂,卻偏偏與公主長得像,于是被迫代替她去往敵國和親秀菱。 傳聞我的和親對象是個殘疾皇子振诬,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,619評論 2 354