2018-06-18 自動(dòng)化測(cè)試selenium在小公司的成功實(shí)踐

原文地址:https://juejin.im/post/5b25e8cae51d4558c4720845?utm_source=gold_browser_extension

邵磊

自動(dòng)化測(cè)試selenium在小公司的成功實(shí)踐

本文可能是目前最完整的一篇selenium(java版)實(shí)踐文章,不是之一。
如果你是java開發(fā)人員拱层,本文將幫助你快速搭建整套selenium自動(dòng)化測(cè)試框架骇两,你可以幫助公司升級(jí)為自動(dòng)化測(cè)試架構(gòu);
如果你是測(cè)試人員拳喻,那你得按照本文多實(shí)踐一下梁剔,遇到不懂的咨詢下公司的java開發(fā),同樣你也可以完成自動(dòng)化測(cè)試架構(gòu)升級(jí)舞蔽。
當(dāng)然啦荣病,如果目前公司已經(jīng)是自動(dòng)化測(cè)試了,那本文就當(dāng)是再次梳理下相關(guān)知識(shí)吧渗柿。

前言

可能提到自動(dòng)化測(cè)試selenium个盆,大家都會(huì)想到用python語言來編寫腳本。但我們選擇了java語言朵栖,因?yàn)槲蚁嘈糯蟛糠止緅ava程序員比python程序員多得多颊亮。而對(duì)于很多測(cè)試人員,并不能熟練使用編程語言陨溅,所以他們需要?jiǎng)e人指導(dǎo)终惑。與其使用更簡(jiǎn)單的python語言,卻看不懂語法门扇,得不到別人幫助雹有;那還不如使用java語言偿渡,無論是語法還是編程思路,都可以快速獲得java開發(fā)人員的幫助霸奕。

背景

可能很多公司已經(jīng)有標(biāo)準(zhǔn)的后端單元測(cè)試代碼溜宽,但是自動(dòng)化測(cè)試需要測(cè)試整個(gè)系統(tǒng),前端是直接展示給用戶的质帅,所以适揉,前端尤為重要,本文就是基于h5的web前端自動(dòng)化測(cè)試煤惩。當(dāng)然啦嫉嘀,這里推薦對(duì)項(xiàng)目進(jìn)行前后端分離,如果項(xiàng)目沒有前后端分離可參考某小公司RESTful魄揉、共用接口吃沪、前后端分離、接口約定的實(shí)踐什猖。

目前互聯(lián)網(wǎng)上關(guān)于selenium完整的文章很少票彪,也很難買到一個(gè)專門講selenium的書籍,這讓很多測(cè)試人員無從下手不狮,而本文會(huì)彌補(bǔ)這一問題降铸,盡可能詳細(xì)完整介紹selenium的實(shí)踐,提供一個(gè)簡(jiǎn)易版的完整項(xiàng)目代碼在github上(因?yàn)楣卷?xiàng)目代碼沒有脫敏摇零,不能直接放到github上)推掸。

相關(guān)知識(shí)

  1. html標(biāo)簽
  2. css樣式
  3. js基礎(chǔ)
  4. java基礎(chǔ)
  5. bat腳本基礎(chǔ)

首先html由標(biāo)簽<x></x>組成,詳細(xì)本文會(huì)在真實(shí)項(xiàng)目中一一介紹驻仅。

正式實(shí)踐

安裝火狐瀏覽器

因?yàn)閟elenium在火狐瀏覽器里谅畅,可以自動(dòng)化錄制腳本,我們通過腳本錄制可以生成出不同的語言腳本噪服,可以省去我們90%的編寫腳本工作量毡泻。 可以安裝最新版的火狐瀏覽器,然后安裝Katalon Recorder (Selenium IDE for Firefox) 使用火狐瀏覽器打開https://addons.mozilla.org/zh-CN/firefox/addon/katalon-automation-record/?src=search

<figure style="display: block; margin: 22px auto; text-align: center;">[圖片上傳中...(image-9271fe-1529311944618-22)]

<figcaption style="display: block; text-align: center; font-size: 1rem; line-height: 1.6; color: rgb(144, 144, 144); margin-top: 2px;"></figcaption>

</figure>

錄制腳本

以百度搜索掘金為例

  1. 地址欄打開百度

  2. 右上角粘优,打開Katalon擴(kuò)展

  3. 點(diǎn)擊Katalon的New

  4. 點(diǎn)擊 Record

  5. 網(wǎng)頁中輸入 掘金網(wǎng)

  6. 打開第一個(gè)掘金官網(wǎng)

  7. 在掘金官網(wǎng)搜索我以前寫的一篇文章 我是如何重構(gòu)整個(gè)研發(fā)項(xiàng)目仇味,促進(jìn)自動(dòng)化運(yùn)維DevOps的落地?

  8. 點(diǎn)擊第一條 我是如何重構(gòu)整個(gè)研發(fā)項(xiàng)目雹顺,促進(jìn)自動(dòng)化運(yùn)維DevOps的落地丹墨?

  9. 點(diǎn)擊Katalon的stop

    <figure style="display: block; margin: 22px auto; text-align: center;">[圖片上傳中...(image-8719e6-1529311944611-0)]

    <figcaption style="display: block; text-align: center; font-size: 1rem; line-height: 1.6; color: rgb(144, 144, 144); margin-top: 2px;"></figcaption>

    </figure>

每執(zhí)行一個(gè)操作右下角都會(huì)提示

<figure style="display: block; margin: 22px auto; text-align: center;">[圖片上傳中...(image-b776e0-1529311944617-21)]

<figcaption style="display: block; text-align: center; font-size: 1rem; line-height: 1.6; color: rgb(144, 144, 144); margin-top: 2px;"></figcaption>

</figure>

錄制后的效果圖

<figure style="display: block; margin: 22px auto; text-align: center;">[圖片上傳中...(image-b74ea7-1529311944617-20)]

<figcaption style="display: block; text-align: center; font-size: 1rem; line-height: 1.6; color: rgb(144, 144, 144); margin-top: 2px;"></figcaption>

</figure>

運(yùn)行、分析腳本

錄制后嬉愧,我們點(diǎn)擊一下play贩挣,可以看到火狐瀏覽器自動(dòng)化的完成了我們剛剛的操作(關(guān)閉彈窗阻止,或者將掘金和百度加入不阻止彈窗列表)

<figure style="display: block; margin: 22px auto; text-align: center;">[圖片上傳中...(image-36d5f7-1529311944617-19)]

<figcaption style="display: block; text-align: center; font-size: 1rem; line-height: 1.6; color: rgb(144, 144, 144); margin-top: 2px;"></figcaption>

</figure>

點(diǎn)擊Export

<figure style="display: block; margin: 22px auto; text-align: center;">[圖片上傳中...(image-427281-1529311944617-18)]

<figcaption style="display: block; text-align: center; font-size: 1rem; line-height: 1.6; color: rgb(144, 144, 144); margin-top: 2px;"></figcaption>

</figure>

可以看到有各種語言 C#、Java王财、katalon卵迂、python2等。 我們先看看python2的腳本

# -*- coding: utf-8 -*-
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import Select
from selenium.common.exceptions import NoSuchElementException
from selenium.common.exceptions import NoAlertPresentException
import unittest, time, re

class Test(unittest.TestCase):
    def setUp(self):
        self.driver = webdriver.Firefox()
        self.driver.implicitly_wait(30)
        self.base_url = "https://www.katalon.com/"
        self.verificationErrors = []
        self.accept_next_alert = True

    def test_(self):
        driver = self.driver
        driver.get("https://www.baidu.com/index.php?tn=monline_3_dg")
        driver.find_element_by_id("kw").click()
        driver.find_element_by_id("kw").clear()
        driver.find_element_by_id("kw").send_keys(u"掘金網(wǎng)")
        driver.find_element_by_xpath("http://div[@id='container']/div[2]/div").click()
        driver.find_element_by_link_text(u"掘金- juejin.im - 一個(gè)幫助開發(fā)者成長(zhǎng)的社區(qū)").click()
        # ERROR: Caught exception [ERROR: Unsupported command [selectWindow | win_ser_1 | ]]
        driver.find_element_by_xpath("http://div[@id='juejin']/div[2]/div/header/div/nav/ul/li[2]/form/input").click()
        driver.find_element_by_xpath("http://div[@id='juejin']/div[2]/div/header/div/nav/ul/li[2]/form/input").click()
        driver.find_element_by_xpath("http://div[@id='juejin']/div[2]/div/header/div/nav/ul/li[2]/form/input").clear()
        driver.find_element_by_xpath("http://div[@id='juejin']/div[2]/div/header/div/nav/ul/li[2]/form/input").send_keys(u"我是如何重構(gòu)整個(gè)研發(fā)項(xiàng)目搪搏,促進(jìn)自動(dòng)化運(yùn)維DevOps的落地狭握?")
        driver.find_element_by_xpath("http://div[@id='juejin']/div[2]/div/header/div/nav/ul/li[2]/form/input").send_keys(Keys.ENTER)
        driver.find_element_by_link_text(u"我是如何重構(gòu)整個(gè)研發(fā)項(xiàng)目闪金,促進(jìn)自動(dòng)化運(yùn)維DevOps的落地疯溺?").click()

    def is_element_present(self, how, what):
        try: self.driver.find_element(by=how, value=what)
        except NoSuchElementException as e: return False
        return True

    def is_alert_present(self):
        try: self.driver.switch_to_alert()
        except NoAlertPresentException as e: return False
        return True

    def close_alert_and_get_its_text(self):
        try:
            alert = self.driver.switch_to_alert()
            alert_text = alert.text
            if self.accept_next_alert:
                alert.accept()
            else:
                alert.dismiss()
            return alert_text
        finally: self.accept_next_alert = True

    def tearDown(self):
        self.driver.quit()
        self.assertEqual([], self.verificationErrors)

if __name__ == "__main__":
    unittest.main()

我們?cè)倏纯磈ava junit腳本

package com.example.tests;

import java.util.regex.Pattern;
import java.util.concurrent.TimeUnit;
import org.junit.*;
import static org.junit.Assert.*;
import static org.hamcrest.CoreMatchers.*;
import org.openqa.selenium.*;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.support.ui.Select;

public class Test {
  private WebDriver driver;
  private String baseUrl;
  private boolean acceptNextAlert = true;
  private StringBuffer verificationErrors = new StringBuffer();

  @Before
  public void setUp() throws Exception {
    driver = new FirefoxDriver();
    baseUrl = "https://www.katalon.com/";
    driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
  }

  @Test
  public void test() throws Exception {
    driver.get("https://www.baidu.com/index.php?tn=monline_3_dg");
    driver.findElement(By.id("kw")).click();
    driver.findElement(By.id("kw")).clear();
    driver.findElement(By.id("kw")).sendKeys("掘金網(wǎng)");
    driver.findElement(By.xpath("http://div[@id='container']/div[2]/div")).click();
    driver.findElement(By.linkText("掘金- juejin.im - 一個(gè)幫助開發(fā)者成長(zhǎng)的社區(qū)")).click();
    // ERROR: Caught exception [ERROR: Unsupported command [selectWindow | win_ser_1 | ]]
    driver.findElement(By.xpath("http://div[@id='juejin']/div[2]/div/header/div/nav/ul/li[2]/form/input")).click();
    driver.findElement(By.xpath("http://div[@id='juejin']/div[2]/div/header/div/nav/ul/li[2]/form/input")).click();
    driver.findElement(By.xpath("http://div[@id='juejin']/div[2]/div/header/div/nav/ul/li[2]/form/input")).clear();
    driver.findElement(By.xpath("http://div[@id='juejin']/div[2]/div/header/div/nav/ul/li[2]/form/input")).sendKeys("我是如何重構(gòu)整個(gè)研發(fā)項(xiàng)目,促進(jìn)自動(dòng)化運(yùn)維DevOps的落地哎垦?");
    driver.findElement(By.xpath("http://div[@id='juejin']/div[2]/div/header/div/nav/ul/li[2]/form/input")).sendKeys(Keys.ENTER);
    driver.findElement(By.linkText("我是如何重構(gòu)整個(gè)研發(fā)項(xiàng)目囱嫩,促進(jìn)自動(dòng)化運(yùn)維DevOps的落地?")).click();
  }

  @After
  public void tearDown() throws Exception {
    driver.quit();
    String verificationErrorString = verificationErrors.toString();
    if (!"".equals(verificationErrorString)) {
      fail(verificationErrorString);
    }
  }

  private boolean isElementPresent(By by) {
    try {
      driver.findElement(by);
      return true;
    } catch (NoSuchElementException e) {
      return false;
    }
  }

  private boolean isAlertPresent() {
    try {
      driver.switchTo().alert();
      return true;
    } catch (NoAlertPresentException e) {
      return false;
    }
  }

  private String closeAlertAndGetItsText() {
    try {
      Alert alert = driver.switchTo().alert();
      String alertText = alert.getText();
      if (acceptNextAlert) {
        alert.accept();
      } else {
        alert.dismiss();
      }
      return alertText;
    } finally {
      acceptNextAlert = true;
    }
  }
}

python代碼量明細(xì)比java要少一點(diǎn)漏设,但是本文講java語言實(shí)踐墨闲。

我們主要關(guān)注 java版 @Test注解的那個(gè)test方法

    driver.get("https://www.baidu.com/index.php?tn=monline_3_dg");
    driver.findElement(By.id("kw")).click();
    driver.findElement(By.id("kw")).clear();
    driver.findElement(By.id("kw")).sendKeys("掘金網(wǎng)");
    driver.findElement(By.xpath("http://div[@id='container']/div[2]/div")).click();
    driver.findElement(By.linkText("掘金- juejin.im - 一個(gè)幫助開發(fā)者成長(zhǎng)的社區(qū)")).click();
    // ERROR: Caught exception [ERROR: Unsupported command [selectWindow | win_ser_1 | ]]
    driver.findElement(By.xpath("http://div[@id='juejin']/div[2]/div/header/div/nav/ul/li[2]/form/input")).click();
    driver.findElement(By.xpath("http://div[@id='juejin']/div[2]/div/header/div/nav/ul/li[2]/form/input")).click();
    driver.findElement(By.xpath("http://div[@id='juejin']/div[2]/div/header/div/nav/ul/li[2]/form/input")).clear();
    driver.findElement(By.xpath("http://div[@id='juejin']/div[2]/div/header/div/nav/ul/li[2]/form/input")).sendKeys("我是如何重構(gòu)整個(gè)研發(fā)項(xiàng)目,促進(jìn)自動(dòng)化運(yùn)維DevOps的落地郑口?");
    driver.findElement(By.xpath("http://div[@id='juejin']/div[2]/div/header/div/nav/ul/li[2]/form/input")).sendKeys(Keys.ENTER);
    driver.findElement(By.linkText("我是如何重構(gòu)整個(gè)研發(fā)項(xiàng)目鸳碧,促進(jìn)自動(dòng)化運(yùn)維DevOps的落地?")).click();

可能很多人已經(jīng)能看懂了

driver.get("https://www.baidu.com/index.php?tn=monline_3_dg");

打開百度

driver.findElement(By.id("kw")).click();

通過id定位到html標(biāo)簽犬性,然后點(diǎn)擊click();清空文本框.clear();輸入 掘金網(wǎng)3個(gè)字 sendKeys("掘金網(wǎng)");

這里我們看一下百度的搜索框代碼

<figure style="display: block; margin: 22px auto; text-align: center;">[圖片上傳中...(image-266b22-1529311944617-17)]

<figcaption style="display: block; text-align: center; font-size: 1rem; line-height: 1.6; color: rgb(144, 144, 144); margin-top: 2px;"></figcaption>

</figure>

<input type="text" class="s_ipt" name="wd" id="kw" maxlength="100" autocomplete="off">

driver.findElement(By.linkText("掘金- juejin.im - 一個(gè)幫助開發(fā)者成長(zhǎng)的社區(qū)")).click();

單擊掘金網(wǎng) 通過linktext定位到標(biāo)簽并點(diǎn)擊瞻离。

后面通過div=juejin一層一層定位到input,最后點(diǎn)擊進(jìn)入文章乒裆。

認(rèn)識(shí)html標(biāo)簽

HTML <input>標(biāo)簽

<input>標(biāo)簽用于搜集用戶信息套利。 根據(jù)不同的 type 屬性值,輸入字段擁有很多種形式鹤耍。輸入字段可以是文本字段肉迫、復(fù)選框、掩碼后的文本控件稿黄、單選按鈕喊衫、按鈕等等。

<form action="form_action.asp" method="get">
  First name: <input type="text" name="fname" />
  Last name: <input type="text" name="lname" />
  <input type="submit" value="Submit" />
</form>

詳情參考 http://www.w3school.com.cn/tags/tag_input.asp

HTML <a>標(biāo)簽

<a> 標(biāo)簽定義超鏈接杆怕,用于從一張頁面鏈接到另一張頁面格侯。
<a> 元素最重要的屬性是 href 屬性,它指示鏈接的目標(biāo)财著。

詳情參考http://www.w3school.com.cn/tags/tag_a.asp

HTML <div>標(biāo)簽

<div>可定義文檔中的分區(qū)或節(jié)(division/section)联四。 <div>標(biāo)簽可以把文檔分割為獨(dú)立的、不同的部分撑教。它可以用作嚴(yán)格的組織工具朝墩,并且不使用任何格式與其關(guān)聯(lián)。 如果用 id 或 class 來標(biāo)記<div>,那么該標(biāo)簽的作用會(huì)變得更加有效收苏。

<div style="color:#00FF00">
  <h3>This is a header</h3>
  <p>This is a paragraph.</p>
</div>

詳情參考http://www.w3school.com.cn/tags/tag_div.asp

…………

其他標(biāo)簽不一一介紹亿卤,可在參考網(wǎng)站上意義看

認(rèn)識(shí)css

這里只講1個(gè)關(guān)鍵的,比如

<div class="css1 css2"> ********</div>

表示這個(gè)div同時(shí)使用了css1和css2樣式鹿霸,只需要知道如果沒辦法在selenium上定位的這個(gè)div排吴,可使用css名定位。

如果有興趣懦鼠,可再看下其他css相關(guān)知識(shí)钻哩。

js基礎(chǔ)

這里講2個(gè)關(guān)鍵

<a onclick="test()">test</a>

上述代碼,點(diǎn)擊a標(biāo)簽會(huì)執(zhí)行js中的test方法肛冶,當(dāng)selenium無法定位到這個(gè)a標(biāo)簽街氢,可以直接調(diào)用test()方法。

可以寫簡(jiǎn)單的js腳本睦袖,彈窗代碼:

alert("hello");

下載谷歌瀏覽器

下載谷歌瀏覽器珊肃,這里可以使用63.0.3239.84版本。 目前來說馅笙,谷歌瀏覽器版本兼容性還是不錯(cuò)的伦乔。

下載selenium driver

https://www.seleniumhq.org/download/

可不下,本文github項(xiàng)目中包含

下載selenium webdriver

https://npm.taobao.org/mirrors/chromedriver/ 需下載和谷歌瀏覽器對(duì)應(yīng)的版本2.40 可不下董习,本文github項(xiàng)目中包含

下載idea開發(fā)工具

https://www.jetbrains.com/idea/

這個(gè)比較復(fù)雜烈和,建議在java開發(fā)人員指導(dǎo)下完成。

selenium

這個(gè)版本是簡(jiǎn)易版阱飘,但足夠

最終效果

<figure style="display: block; margin: 22px auto; text-align: center;">[圖片上傳中...(image-297cce-1529311944617-16)]

<figcaption style="display: block; text-align: center; font-size: 1rem; line-height: 1.6; color: rgb(144, 144, 144); margin-top: 2px;"></figcaption>

</figure>

我們通過錄制selenium腳本斥杜,編輯,提交到git庫沥匈,由jenkins自動(dòng)化編譯出jar包蔗喂,通過bat命令在任意一臺(tái)pc端執(zhí)行(默認(rèn)開發(fā)人員提交代碼后自動(dòng)執(zhí)行所有模塊)。按功能模塊高帖,測(cè)試項(xiàng)目缰儿,生成測(cè)試報(bào)告。對(duì)測(cè)試不通過的模塊

最大化

driver.manage().window().maximize();

打開頁面

driver.get("https://www.baidu.com");

定位元素

<figure style="display: block; margin: 22px auto; text-align: center;">[圖片上傳中...(image-ce2177-1529311944616-15)]

<figcaption style="display: block; text-align: center; font-size: 1rem; line-height: 1.6; color: rgb(144, 144, 144); margin-top: 2px;"></figcaption>

</figure>

多個(gè)相同時(shí)散址,返回第一個(gè)乖阵,沒有找到會(huì)拋異常NoSuchElementException

WebElement element = driver.findElement(*);

當(dāng)返回多個(gè)時(shí):

List<WebElement> elements = driver.findElements(*);

定位元素方式

<input class="input_class input_class2" type="text" name="user-name" id="user-id" /> 

通過id定位

WebElement element = driver.findElement(By.id("user-id"));

通過name定位

WebElement element = driver.findElement(By.name("user-name"));

通過className定位

WebElement element = driver.findElement(By.className("input_class.input_class2"));

注意多個(gè)class用小數(shù)點(diǎn)隔開,也可以使用cssSelector定位

WebElement element = driver.findElement(By.cssSelector("input"));

通過linkText定位预麸,如:

WebElement element = driver.findElement(By.linkText("我是如何重構(gòu)整個(gè)研發(fā)項(xiàng)目瞪浸,促進(jìn)自動(dòng)化運(yùn)維DevOps的落地?"));

意思就是鏈接內(nèi)容定位

通過partialLinkText定位吏祸,模糊內(nèi)容定位对蒲,和上相似

WebElement element = driver.findElement(By.linkText("我是如何重構(gòu)整個(gè)研發(fā)項(xiàng)目?"));

通過tagName定位

WebElement element = driver.findElement(By.tagName("form"));

通過xpath定位

WebElement element = driver.findElement(By.xpath("http://input[@id='passwd-id']")); 

這個(gè)最為復(fù)雜,最簡(jiǎn)單的版本是

//標(biāo)簽類型[@屬性名=屬性值]

但也可以定位第幾個(gè)

//input[4]

其中[]中還可以增加邏輯and or表達(dá)式

WebElement element = driver.findElement(By.xpath("http://input[@type='text' and @name='user-name']"));
WebElement element = driver.findElement(By.xpath("http://input[@type='text' or @name='user-name']"));

[]中也可以增加start-with蹈矮、ends-with砰逻、contains,比如

WebElement element = driver.findElement(By.xpath("http://input[start-with(@id,'user-')]"));
WebElement element = driver.findElement(By.xpath("http://input[ends-with(@id,'user-')]"));
WebElement element = driver.findElement(By.xpath("http://input[contains(@id,'user-')]"));

還可以 任意屬性名

WebElement element = driver.findElement(By.xpath("http://input[@*='user-name']"));

更多xpath使用方法見 http://www.w3school.com.cn/xpath/index.asp

單擊某個(gè)元素

.click()

清空input

.clear();

input中輸入內(nèi)容

.sendKeys("掘金網(wǎng)");

如果是上傳附件泛鸟,可直接sendKeys路徑

.sendKeys("c:\shao.png");

得到input內(nèi)容

.getText();

下拉框

<figure style="display: block; margin: 22px auto; text-align: center;">[圖片上傳中...(image-14d2e2-1529311944616-14)]

<figcaption style="display: block; text-align: center; font-size: 1rem; line-height: 1.6; color: rgb(144, 144, 144); margin-top: 2px;"></figcaption>

</figure>

    Select select = new Select(driver.findElement(By.id("frequency")));
    select.selectByValue("1");
    driver.findElement(By.id("validDays")).click();

    select.selectByValue("a"); 
    select.deselectAll();
    select.deselectByValue("a");
    select.deselectByVisibleText("");
    select.getAllSelectedOptions();
    select.getFirstSelectedOption(); 

單選框

WebElement radio=driver.findElement(By.id("radio"));
radio.click();&emsp;&emsp;&emsp;&emsp;   //選擇某個(gè)選項(xiàng)
radio.clear();&emsp;&emsp;&emsp;&emsp;  //清空選項(xiàng)
radio.isSelected();&emsp;&emsp;//判斷某個(gè)單選項(xiàng)是否被選中

復(fù)選框

WebElement checkbox = driver.findElement(By.id("checkbox"));
checkbox.clear();       //清空選項(xiàng)
checkbox.isSelected(); //是否選中

判斷是否可點(diǎn)擊

isEnabled()

alert框操作

Alert alert = driver.switchTo().alert();
alert.accept();&emsp;&emsp;//確定
alert.dismiss();&emsp; //取消

iframe切換(重點(diǎn)

可能很多老的項(xiàng)目都有iframe蝠咆,錄制腳本的時(shí)候正常錄制,可執(zhí)行的時(shí)候北滥,卻無法執(zhí)行刚操,這個(gè)時(shí)候,需要切換iframe

driver.switchTo().defaultContent();&emsp;//回到默認(rèn)的頁面
driver.switchTo().frame("leftFrame"); //切換到某個(gè)iframe

切換iframe碑韵,結(jié)束后赡茸,記得切換回默認(rèn)頁面缎脾。

        driver.findElement(By.linkText("導(dǎo)入模板")).click();
        WebElement iframe = driver.findElement(By.id("layui-layer-iframe1"));
        driver.switchTo().frame(iframe);
        Thread.sleep(2000);
        driver.findElement(By.linkText("引用")).click();
        driver.findElement(By.xpath("http://button[@type='submit']")).click();
        driver.findElement(By.xpath("(//button[@type='button'])[3]")).click();
        Thread.sleep(1000);
        driver.findElement(By.linkText("學(xué)生")).click();

以上摘自項(xiàng)目代碼祝闻,僅供參考

執(zhí)行 js

    JavascriptExecutor js = (JavascriptExecutor) driver;
    js.executeScript("viewDetail('1f50555e409a4597a027ff415ce6c9b4','09','2018')");

執(zhí)行內(nèi)部viewDetail方法

延時(shí)操作(重要

很多時(shí)候我們需要延時(shí),這時(shí)使用

Thread.sleep(1000);//延時(shí)1000毫秒

許多錯(cuò)誤是因?yàn)樾枰却龝r(shí)間遗菠,嘗試增加一個(gè)延時(shí)联喘,也許這個(gè)問題就過去了。

項(xiàng)目代碼

假設(shè)辙纬,我們產(chǎn)品有多個(gè)環(huán)境豁遭,我們定義一個(gè)environments數(shù)組,(當(dāng)-1時(shí),提示用戶輸入),有多個(gè)模塊(當(dāng)-1時(shí)年缎,提示用戶輸入)八匠,最終代碼如下,執(zhí)行后暮的,錯(cuò)誤報(bào)告會(huì)通過郵件發(fā)送到指定郵箱或者其他地方。

運(yùn)行效果圖

<figure style="display: block; margin: 22px auto; text-align: center;">[圖片上傳中...(image-8f91cd-1529311944616-13)]

<figcaption style="display: block; text-align: center; font-size: 1rem; line-height: 1.6; color: rgb(144, 144, 144); margin-top: 2px;"></figcaption>

</figure>

import org.openqa.selenium.*;
import org.openqa.selenium.chrome.ChromeDriver;
import webfunction.*;

import java.util.Scanner;

public class Main {
    private static WebDriver driver;
    private static String baseUrl;
    private boolean acceptNextAlert = true;
    /**
     * 各個(gè)環(huán)境
     * */
    private static String[] environments = {"環(huán)境1", "環(huán)境2", "環(huán)境3", "環(huán)境4", "環(huán)境5", "環(huán)境6"};
    /**
     * 錯(cuò)誤日志
     * */
    private static StringBuffer verificationErrors = new StringBuffer();
    /**
     * 是否處于debug模式
     */
    private static boolean debug = false;
    /**
     * -1為手動(dòng)模式,否則為指定數(shù)字
     * */
    private static String environment = "-1";
    /**
     * -1為手動(dòng)模式盯腌,否則為指定數(shù)字
     * */
    private static String methods = "-1";

    public static void main(String[] args) throws Exception {
        //引用火狐瀏覽器驅(qū)動(dòng)
        System.setProperty("webdriver.chrome.driver", "C:\\selenium\\chromedriver.exe");

        //定義用戶名密碼
        String uname, upw;
        Scanner sc = new Scanner(System.in);
        System.out.println("請(qǐng)選擇環(huán)境");
        for (int i = 0; i < environments.length; i++) {
            System.out.println(i + ":" + environments[i]);
        }
        if ("-1".equals(environment)) {
            environment = sc.next();
        }

        System.out.println("請(qǐng)輸入需要測(cè)試的功能,英文逗號(hào)隔開");
        if ("-1".equals(methods)) {
            methods = sc.next();
        }
        driver = new ChromeDriver();

        System.out.println("您選擇的是" + environments[Integer.valueOf(environment)]);
        switch (environment) {
            case "0":
                baseUrl = "http://*.*.*.*/";
                uname = "admin";
                upw = "admin";
                testManage(baseUrl, uname, upw, methods, driver);
                break;
            case "1":
                baseUrl = "http://*.*.*.*/";
                uname = "admin";
                upw = "admin";
                testManage(baseUrl, uname, upw, methods, driver);
                break;
            case "2":
                //等等等……
                break;
        }

    }

    private static void testManage(String url, String uname, String upw, String methods, WebDriver driver) throws InterruptedException {
        //先登錄管理端
        WebLogin.webLogin(driver, url, uname, upw);
        //然后測(cè)試所有模塊
        String[] strArray = null;
        strArray = methods.split(",");
        for (int i = 0; i < strArray.length; i++) {
            switch (strArray[i]) {
                case "0":
                    try {
                        // 系統(tǒng)基礎(chǔ)管理 - 用戶管理 - 新增用戶
                        WebSystemManage.addnewUser(driver, url);     
                    } catch (Exception e) {
                        verificationErrors.append("系統(tǒng)基礎(chǔ)管理 - 用戶管理 - 新增用戶   出錯(cuò)");
                        log(e);
                    }
                    break;
                case "1":
                    try {
                        // 系統(tǒng)基礎(chǔ)管理 - 用戶管理 - 編輯用戶
                        WebSystemManage.editUser(driver, url);       
                    } catch (Exception e) {
                        System.out.println("系統(tǒng)基礎(chǔ)管理 - 用戶管理 - 編輯用戶   出錯(cuò)");
                        log(e);
                    }
                    break;
                default:
                    break;
            }
        }
        report(verificationErrors);
    }

    private static void report(StringBuffer verificationErrors) {
        //發(fā)送郵件
    }

    /**
     * 根據(jù)debug變量是否輸出日志
     * @param e
     */
    private static void log(Exception e) {
        if (debug) {
            e.printStackTrace();
        }
    }

    private static boolean isElementPresent(By by) {
        try {
            driver.findElement(by);
            return true;
        } catch (NoSuchElementException e) {
            return false;
        }
    }

    private static boolean isAlertPresent() {
        try {
            driver.switchTo().alert();
            return true;
        } catch (NoAlertPresentException e) {
            return false;
        }
    }

    private static String closeAlertAndGetItsText() {
        try {
            Alert alert = driver.switchTo().alert();
            String alertText = alert.getText();
            if (acceptNextAlert) {
                alert.accept();
            } else {
                alert.dismiss();
            }
            return alertText;
        } finally {
            acceptNextAlert = true;
        }
    }
}

代碼那么多其實(shí)我們只關(guān)注 public static void main(String[] args) throws Exception {}內(nèi)的內(nèi)容陨瘩,比如腕够,我們想運(yùn)行我們最初錄制的掘金腳本,只需將那端我要求特別關(guān)注的代碼放到里面即可舌劳,具體代碼如下:

import org.openqa.selenium.*;
import org.openqa.selenium.chrome.ChromeDriver;

public class Main {
    private static WebDriver driver;

    public static void main(String[] args) throws Exception {
        //引用火狐瀏覽器驅(qū)動(dòng)
        System.setProperty("webdriver.chrome.driver", "C:\\selenium\\chromedriver.exe");
        driver = new ChromeDriver();
        driver.manage().window().maximize();
        //以下為Katalon Recorder錄制后的腳本
        driver.get("https://www.baidu.com/index.php?tn=monline_3_dg");
        Thread.sleep(2000);
        driver.findElement(By.id("kw")).click();
        driver.findElement(By.id("kw")).clear();
        driver.findElement(By.id("kw")).sendKeys("掘金網(wǎng)");
        Thread.sleep(100);
        driver.findElement(By.id("su")).click();
        Thread.sleep(1000);
        driver.findElement(By.xpath("http://div[@id='container']/div[2]/div")).click();
        driver.findElement(By.linkText("掘金- juejin.im - 一個(gè)幫助開發(fā)者成長(zhǎng)的社區(qū)")).click();
        Thread.sleep(3000);
        // ERROR: Caught exception [ERROR: Unsupported command [selectWindow | win_ser_1 | ]]
        driver.findElement(By.xpath("http://div[@id='juejin']/div[2]/div/header/div/nav/ul/li[2]/form/input")).click();
        driver.findElement(By.xpath("http://div[@id='juejin']/div[2]/div/header/div/nav/ul/li[2]/form/input")).click();
        driver.findElement(By.xpath("http://div[@id='juejin']/div[2]/div/header/div/nav/ul/li[2]/form/input")).clear();
        driver.findElement(By.xpath("http://div[@id='juejin']/div[2]/div/header/div/nav/ul/li[2]/form/input")).sendKeys("我是如何重構(gòu)整個(gè)研發(fā)項(xiàng)目帚湘,促進(jìn)自動(dòng)化運(yùn)維DevOps的落地?");
        driver.findElement(By.xpath("http://div[@id='juejin']/div[2]/div/header/div/nav/ul/li[2]/form/input")).sendKeys(Keys.ENTER);
        Thread.sleep(2000);
        driver.findElement(By.linkText("我是如何重構(gòu)整個(gè)研發(fā)項(xiàng)目甚淡,促進(jìn)自動(dòng)化運(yùn)維DevOps的落地大诸?")).click();
    }
}

上述代碼中注釋內(nèi)是Katalon Recorder導(dǎo)出的腳本,但是我們?cè)黾恿艘恍┭訒r(shí)操作,selenium延時(shí)有很3種:普通sleep底挫、顯示等待方式恒傻、隱式等待方式。這里先簡(jiǎn)單粗暴一下建邓,用Thread.sleep(*);延時(shí)盈厘,比如打開百度延時(shí)2秒、輸入“掘金網(wǎng)”延時(shí)100毫秒官边、搜索后延時(shí)3秒…………

很遺憾沸手,我們代碼報(bào)錯(cuò):

<figure style="display: block; margin: 22px auto; text-align: center;">[圖片上傳中...(image-6529ff-1529311944614-12)]

<figcaption style="display: block; text-align: center; font-size: 1rem; line-height: 1.6; color: rgb(144, 144, 144); margin-top: 2px;"></figcaption>

</figure>

大概意思說超時(shí)沒有找到那個(gè)搜索框,由于各種各樣的原因注簿,會(huì)導(dǎo)致我們?cè)诨鸷鼮g覽器中錄制的腳本在java代碼中的谷歌瀏覽器里無法兼容契吉,這個(gè)時(shí)候我們需要去分析一下具體邏輯。

這里是由于新窗口需要切換window诡渴,可使用下述代碼切換(替換代碼中// ERROR: Caught exception [ERROR: Unsupported command [selectWindow | win_ser_1 | ]]這行即可)捐晶。

        Set<String> windowHandles = driver.getWindowHandles();
        String windowHandle = driver.getWindowHandle();
        for (String handle : windowHandles) {
            if (!handle.equals(driver.getWindowHandle())) {
                driver.switchTo().window(handle);
                break;
            }
        }

導(dǎo)出的腳本By.xpath("http://div[@id='juejin']/div[2]/div/header/div/nav/ul/li[2]/form/input")這一句很復(fù)雜,我們?cè)囍?jiǎn)化它妄辩。

<figure style="display: block; margin: 22px auto; text-align: center;">[圖片上傳中...(image-ef80e8-1529311944614-11)]

<figcaption style="display: block; text-align: center; font-size: 1rem; line-height: 1.6; color: rgb(144, 144, 144); margin-top: 2px;"></figcaption>

</figure>

<input data-v-5ce25e66="" maxlength="32" placeholder="搜索掘金" class="search-input">

首先搜索下search-input樣式惑灵,看該頁面是否只有一個(gè)search-input樣式。

<figure style="display: block; margin: 22px auto; text-align: center;">[圖片上傳中...(image-a11031-1529311944614-10)]

<figcaption style="display: block; text-align: center; font-size: 1rem; line-height: 1.6; color: rgb(144, 144, 144); margin-top: 2px;"></figcaption>

</figure>

果然search-input樣式只有一個(gè)標(biāo)簽眼耀。

于是我們將

By.xpath("http://div[@id='juejin']/div[2]/div/header/div/nav/ul/li[2]/form/input")
//改為
By.className("search-input")

最終代碼

import org.openqa.selenium.*;
import org.openqa.selenium.chrome.ChromeDriver;

import java.util.Set;

public class Main {
    private static WebDriver driver;

    public static void main(String[] args) throws Exception {
        //引用火狐瀏覽器驅(qū)動(dòng)
        System.setProperty("webdriver.chrome.driver", "C:\\selenium\\chromedriver.exe");
        driver = new ChromeDriver();
        driver.manage().window().maximize();
        driver.get("https://www.baidu.com/index.php?tn=monline_3_dg");
        Thread.sleep(2000);
        driver.findElement(By.id("kw")).click();
        driver.findElement(By.id("kw")).clear();
        driver.findElement(By.id("kw")).sendKeys("掘金網(wǎng)");
        Thread.sleep(100);
        driver.findElement(By.id("su")).click();
        Thread.sleep(1000);
        driver.findElement(By.xpath("http://div[@id='container']/div[2]/div")).click();
        driver.findElement(By.linkText("掘金- juejin.im - 一個(gè)幫助開發(fā)者成長(zhǎng)的社區(qū)")).click();
        Thread.sleep(7000);
        Set<String> windowHandles = driver.getWindowHandles();
        String windowHandle = driver.getWindowHandle();
        for (String handle : windowHandles) {
            if (!handle.equals(driver.getWindowHandle())) {
                driver.switchTo().window(handle);
                break;
            }
        }
        // ERROR: Caught exception [ERROR: Unsupported command [selectWindow | win_ser_1 | ]]
        driver.findElement(By.xpath("http://div[@id='juejin']/div[2]/div/header/div/nav/ul/li[2]/form/input")).click();
        driver.findElement(By.xpath("http://div[@id='juejin']/div[2]/div/header/div/nav/ul/li[2]/form/input")).click();
        driver.findElement(By.xpath("http://div[@id='juejin']/div[2]/div/header/div/nav/ul/li[2]/form/input")).clear();
        driver.findElement(By.xpath("http://div[@id='juejin']/div[2]/div/header/div/nav/ul/li[2]/form/input")).sendKeys("我是如何重構(gòu)整個(gè)研發(fā)項(xiàng)目英支,促進(jìn)自動(dòng)化運(yùn)維DevOps的落地?");
        driver.findElement(By.xpath("http://div[@id='juejin']/div[2]/div/header/div/nav/ul/li[2]/form/input")).sendKeys(Keys.ENTER);
        Thread.sleep(2000);
        driver.findElement(By.linkText("我是如何重構(gòu)整個(gè)研發(fā)項(xiàng)目哮伟,促進(jìn)自動(dòng)化運(yùn)維DevOps的落地干花?")).click();
    }
}

編譯打包

<figure style="display: block; margin: 22px auto; text-align: center;">[圖片上傳中...(image-d97ba6-1529311944614-9)]

<figcaption style="display: block; text-align: center; font-size: 1rem; line-height: 1.6; color: rgb(144, 144, 144); margin-top: 2px;"></figcaption>

</figure>

<figure style="display: block; margin: 22px auto; text-align: center;">[圖片上傳中...(image-8d386e-1529311944614-8)]

<figcaption style="display: block; text-align: center; font-size: 1rem; line-height: 1.6; color: rgb(144, 144, 144); margin-top: 2px;"></figcaption>

</figure>

得到selenium.jar包,可復(fù)制到C:\selenium下楞黄,和chromedriver.exe同級(jí)池凄。

<figure style="display: block; margin: 22px auto; text-align: center;">[圖片上傳中...(image-6344c3-1529311944614-7)]

<figcaption style="display: block; text-align: center; font-size: 1rem; line-height: 1.6; color: rgb(144, 144, 144); margin-top: 2px;"></figcaption>

</figure>

輸入cmd命令

C:\Users\Administrator>cd C:\selenium

C:\selenium>java -jar selenium2.jar

即可自動(dòng)化運(yùn)行,非windows系統(tǒng)下載2.40其他版本https://npm.taobao.org/mirrors/chromedriver/2.40/

<figure style="display: block; margin: 22px auto; text-align: center;">[圖片上傳中...(image-380400-1529311944613-6)]

<figcaption style="display: block; text-align: center; font-size: 1rem; line-height: 1.6; color: rgb(144, 144, 144); margin-top: 2px;"></figcaption>

</figure>

github項(xiàng)目運(yùn)行

https://github.com/qq273681448/selenium

為了防止有讀者沒有改maven庫鏡像谅辣,所以把lib包都放在項(xiàng)目中了修赞。直接使用idea打開,可能有些配置需要改桑阶,可參考

<figure style="display: block; margin: 22px auto; text-align: center;">[圖片上傳中...(image-5f01b-1529311944613-5)]

<figcaption style="display: block; text-align: center; font-size: 1rem; line-height: 1.6; color: rgb(144, 144, 144); margin-top: 2px;"></figcaption>

</figure>

<figure style="display: block; margin: 22px auto; text-align: center;">[圖片上傳中...(image-7f2bdb-1529311944613-4)]

<figcaption style="display: block; text-align: center; font-size: 1rem; line-height: 1.6; color: rgb(144, 144, 144); margin-top: 2px;"></figcaption>

</figure>

<figure style="display: block; margin: 22px auto; text-align: center;">[圖片上傳中...(image-9fe919-1529311944613-3)]

<figcaption style="display: block; text-align: center; font-size: 1rem; line-height: 1.6; color: rgb(144, 144, 144); margin-top: 2px;"></figcaption>

</figure>

<figure style="display: block; margin: 22px auto; text-align: center;">[圖片上傳中...(image-ca091e-1529311944613-2)]

<figcaption style="display: block; text-align: center; font-size: 1rem; line-height: 1.6; color: rgb(144, 144, 144); margin-top: 2px;"></figcaption>

</figure>

<figure style="display: block; margin: 22px auto; text-align: center;">[圖片上傳中...(image-a8a55c-1529311944613-1)]

<figcaption style="display: block; text-align: center; font-size: 1rem; line-height: 1.6; color: rgb(144, 144, 144); margin-top: 2px;"></figcaption>

</figure>

寫在最后

至此柏副,一個(gè)基礎(chǔ)版的selenium框架就搭好了,后續(xù)蚣录,可以連接數(shù)據(jù)庫割择,從庫中隨機(jī)取出帳號(hào),進(jìn)行項(xiàng)目測(cè)試萎河。也可以配合bat腳本荔泳,實(shí)現(xiàn)自動(dòng)化測(cè)試以及報(bào)告生成蕉饼。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市玛歌,隨后出現(xiàn)的幾起案子昧港,更是在濱河造成了極大的恐慌,老刑警劉巖支子,帶你破解...
    沈念sama閱讀 221,430評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件创肥,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡值朋,警方通過查閱死者的電腦和手機(jī)叹侄,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,406評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來昨登,“玉大人趾代,你說我怎么就攤上這事》崂保” “怎么了撒强?”我有些...
    開封第一講書人閱讀 167,834評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)糯俗。 經(jīng)常有香客問我尿褪,道長(zhǎng)睦擂,這世上最難降的妖魔是什么得湘? 我笑而不...
    開封第一講書人閱讀 59,543評(píng)論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮顿仇,結(jié)果婚禮上淘正,老公的妹妹穿的比我還像新娘。我一直安慰自己臼闻,他們只是感情好鸿吆,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,547評(píng)論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著述呐,像睡著了一般惩淳。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上乓搬,一...
    開封第一講書人閱讀 52,196評(píng)論 1 308
  • 那天思犁,我揣著相機(jī)與錄音,去河邊找鬼进肯。 笑死激蹲,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的江掩。 我是一名探鬼主播学辱,決...
    沈念sama閱讀 40,776評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼乘瓤,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了策泣?” 一聲冷哼從身側(cè)響起衙傀,我...
    開封第一講書人閱讀 39,671評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎萨咕,沒想到半個(gè)月后差油,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,221評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡任洞,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,303評(píng)論 3 340
  • 正文 我和宋清朗相戀三年蓄喇,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片交掏。...
    茶點(diǎn)故事閱讀 40,444評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡妆偏,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出盅弛,到底是詐尸還是另有隱情钱骂,我是刑警寧澤,帶...
    沈念sama閱讀 36,134評(píng)論 5 350
  • 正文 年R本政府宣布挪鹏,位于F島的核電站见秽,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏讨盒。R本人自食惡果不足惜解取,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,810評(píng)論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望返顺。 院中可真熱鬧禀苦,春花似錦、人聲如沸遂鹊。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,285評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽秉扑。三九已至慧邮,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間舟陆,已是汗流浹背误澳。 一陣腳步聲響...
    開封第一講書人閱讀 33,399評(píng)論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留吨娜,地道東北人脓匿。 一個(gè)月前我還...
    沈念sama閱讀 48,837評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像宦赠,于是被迫代替她去往敵國和親陪毡。 傳聞我的和親對(duì)象是個(gè)殘疾皇子米母,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,455評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容