Selenium自動化測試在PageObject下的架構與測試報告生成

Selenium由於其適用多種語言(本文使用的語言爲java),在自動化測試領域中的使用用越來越多。使用Selenium的方式有很多,能使用的工具也很多。PageObject模式的使用提高了測試代碼的可讀性與可維護性,同時一定程度減少了測試代碼量,降低了測試用例與測試功能間的耦合程度。

目前遇到的問題:

(1)Selenium自動化測試大部分的操作都由WebDriver完成,比如在進行一次點擊操作時,首先要獲取Dom元素(dom元素的獲取方法有很多,詳見API即可),然後再調用點擊的方法,每一步都要進行獲取再執行的操作多有冗餘。                                                                                                                                                                                                                      

(2)在編寫測試用例時,需要初始化WebDriver,對於WebDriver的初始化在每一個頁面的測試case類裏都要編寫一次,這裏也存在冗餘。


(3)如何控制兩步操作間的執行時間。

對於問題(1)代碼冗餘的問題,筆者將WebDriver中的方法重新包裝了一遍。

定義接口WebDriverWrapper

package com.test.sahagin.wrapper;

import org.openqa.selenium.WebElement;

public interface WebDriverWrapper {
	
	/**
	 * 根據標籤ID獲取 標籤元素
	 * @param id
	 * @return
	 */
    WebElement getElementById(String id);
    
	/**
	 * 根據標籤name獲取 標籤元素
	 * @param name
	 * @return
	 */
	WebElement getElementByName(String name);
	
	/**
	 * 根據標籤className獲取 標籤元素
	 * @param className
	 * @return
	 */
	 WebElement getElementByClassName(String className);
	 
	/**
	 * 根據標籤Css 選擇器獲取 標籤元素
	 * @param selector
	 * @return
	 */
	 WebElement getElementByCssSelector(String selector);
	 
	/**
	 * 根據標籤標籤名稱獲取 標籤元素
	 * @param tagName
	 * @return
	 */
     WebElement getElementByTagName(String tagName);
	
	//******************點擊操作********************//
	
	void clickByJs(String id);
	
    void clickById(String id);
	
	void clickByName(String name);
	//*****************情空操作********************//
	void clearById(String id);
	
	//*****************賦值操作*******************//
	void sendKeysById(String id, String content);
	
	
	//*****************執行js操作*****************//
	void executeJsById(String id, String js);
	
	void executeJs(String js);
	/**
	 * 選擇複選框進行賦值
	 * @param formId
	 * @param tagName
	 * @param value
	 */
	void selectCheckBox(String tagName, String value[]);
	
	
	/**
	 * 通過下拉框option的text內容選擇下拉框選項
	 * @param selectId  下拉框ID
	 * @param text 下拉框選項內容
	 */
	void selectDropDownListByText(String selectId, String text);
	
	/**
	 * 通過下拉框option的value內容選擇下拉框選項
	 * @param selectId  下拉框ID
	 * @param value 下拉框選項值
	 */
	void selectDropDownListByValue(String selectId, String value);
	
	/**
	 * 通過下拉框option的索引內容選擇下拉框選項
	 * @param selectId  下拉框ID
	 * @param value 下拉框選項值
	 */
	void selectDropDownListByIndex(String selectId, int index);
}


定義實現:WebDriverWrapperImpl                 

package com.test.sahagin.wrapper;

import java.util.List;

import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.Select;

public final class WebDriverWrapperImpl implements WebDriverWrapper{
	
	private WebDriver webDriver;

	public WebDriverWrapperImpl(WebDriver webDriver) {
		super();
		this.webDriver = webDriver;
	}
	
	/**
	 * 根據標籤ID獲取 標籤元素
	 * @param id
	 * @return
	 */
	public WebElement getElementById(String id) {
		return webDriver.findElement(By.id(id));
	}
	
	/**
	 * 根據標籤name獲取 標籤元素
	 * @param name
	 * @return
	 */
	public WebElement getElementByName(String name) {
		return webDriver.findElement(By.name(name));
	}
	
	/**
	 * 根據標籤className獲取 標籤元素
	 * @param className
	 * @return
	 */
	public WebElement getElementByClassName(String className) {
		return webDriver.findElement(By.className(className));
	}
	
	/**
	 * 根據標籤Css 選擇器獲取 標籤元素
	 * @param selector
	 * @return
	 */
	public WebElement getElementByCssSelector(String selector) {
		return webDriver.findElement(By.cssSelector(selector));
	}
	
	/**
	 * 根據標籤標籤名稱獲取 標籤元素
	 * @param tagName
	 * @return
	 */
	public WebElement getElementByTagName(String tagName) {
		return webDriver.findElement(By.tagName(tagName));
	}
	
	
	public List<WebElement> getElementByPath(String path) {
		return webDriver.findElements(By.xpath(path));
	}
	
	//******************點擊操作********************//
	
	public void clickByJs(String id) {
		executeJsById(id,"arguments[0].click()");
	}
	
	public void clickById(String id) {
		this.getElementById(id).click();
	}
	
	public void clickByName(String name) {
		this.getElementByName(name).click();
	}
	
	//*****************情空操作********************//
	public void clearById(String id) {
		this.getElementById(id).clear();
	}
	
	
	//*****************賦值操作*******************//
	public void sendKeysById(String id, String content) {
		this.clearById(id);
		this.getElementById(id).sendKeys(content);;
	}
	
	
	//*****************執行js操作*****************//
	public void executeJsById(String id, String js) {
		WebElement ele = this.getElementById(id);
		((JavascriptExecutor)webDriver).executeScript(js, ele);
	}
	
	@Override
	public void executeJs(String js) {
		((JavascriptExecutor)webDriver).executeAsyncScript(js);
		
	}

	@Override
	public void selectCheckBox(String tagName, String[] value) {
//		List<WebElement> eles = this.getElementByPath("//*[@id='" + formId + "']/**/input[@name='"+ tagName +"']");
		List<WebElement> eles = webDriver.findElements(By.name(tagName));
		if (eles != null) {
			for (WebElement ele : eles) {
				for (int i = 0; i < value.length; i ++) {
					WebElement ch = ele.findElement(By.xpath("/following-sibling::span[2]"));
					if (ch != null && ch.getText().equals(value[i]))
						ele.click();
				}
			}
		}
	}

	
	@Override
	public void selectDropDownListByText(String selectId, String text) {
		Select select = new Select(getElementById(selectId));
		select.selectByVisibleText(text);
	}

	@Override
	public void selectDropDownListByValue(String selectId, String value) {
		Select select = new Select(getElementById(selectId));
		select.selectByValue(value);
	}

	@Override
	public void selectDropDownListByIndex(String selectId, int index) {
		// TODO Auto-generated method stub
		Select select = new Select(getElementById(selectId));
		select.selectByIndex(index);
	}

	
	
	
}


這樣在執行頁面操作時,調用裏面的方法就可以了。並且使用PageObject模式 之前注入的是WebDriver,現在需要注入WebDriverWrapper。再新建一個PageObject類時,可以直接繼承BaseTestPage

package com.test.pages;

import org.sahagin.runlib.external.TestDoc;

import com.fujitsu.test.sahagin.wrapper.WebDriverWrapper;

public class BaseTestPage {
	protected WebDriverWrapper wd;

	public BaseTestPage() {
		super();
	}
	
	public BaseTestPage(WebDriverWrapper wd) {
		super();
		this.wd = wd;
	}
	//在這裏可以添加頁面共有的操作。
	@TestDoc("「管理メニュー」を押下する")
	public void clickManageMenu() {
		wd.clickByJs("managementMenu");
	}
	
	@TestDoc("「利用者一覧」を押下する")
	public void clickUserList() {
		wd.clickByJs("userList");
	}
	
	@TestDoc("「屬性一覧」を押下する")
	public void clickAttributeList() {
		wd.clickByJs("attributeList");
	}
	
	@TestDoc("「共通公開範囲一覧」を押下する")
	public void clickPublishList() {
		wd.clickByJs("publishList");
	}
	
	@TestDoc("「案件書式一覧」を押下する")
	public void clickItemFormatList() {
		wd.clickByJs("itemFormatList");
	}
	
	@TestDoc("「案件ロック一覧」を押下する")
	public void clickItemLockList() {
		wd.clickByJs("itemLockList");
	}
}


對於問題(2)

首先寫一個工具類用於初始化WebDriver。

package com.test.sahagin.util;

import org.openqa.selenium.Platform;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.ie.InternetExplorerDriver;
import org.openqa.selenium.remote.DesiredCapabilities;

public class WebDriverUtil {
	
	private static WebDriverUtil webDriverUtil = new WebDriverUtil();
	
	private WebDriverUtil() {}
	
	public static WebDriverUtil getInstance() {
		return webDriverUtil;
	}
	
	public WebDriver initWebDriver() {
		DesiredCapabilities capabilities = configDesiredCapabilities();
		return new InternetExplorerDriver(capabilities);
	}
	
	private DesiredCapabilities configDesiredCapabilities() {
		DesiredCapabilities capabilities = DesiredCapabilities.internetExplorer();
        capabilities.setCapability(InternetExplorerDriver.INTRODUCE_FLAKINESS_BY_IGNORING_SECURITY_DOMAINS,true);
        capabilities.setPlatform(Platform.WINDOWS);
        capabilities.setCapability("silent", true);
        capabilities.setCapability("ignoreZoomSetting", true);
		return capabilities;
	}

}

然後寫一個BaseTestPage

package com.test.features;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.concurrent.TimeUnit;

import org.openqa.selenium.WebDriver;
import org.sahagin.runlib.external.adapter.webdriver.WebDriverAdapter;

import com.fujitsu.test.pages.LoginPage;
import com.fujitsu.test.pages.PageURL;
import com.fujitsu.test.sahagin.util.DynamicProxy;
import com.fujitsu.test.sahagin.util.WebDriverUtil;
import com.fujitsu.test.sahagin.wrapper.WebDriverWrapper;
import com.fujitsu.test.sahagin.wrapper.WebDriverWrapperImpl;

public class BaseTestPage {
	
	protected WebDriverWrapper webDriverWrapper;
		
	protected WebDriver webDriver;
	 
	protected String url;
	
	public void init() {
		webDriver = WebDriverUtil.getInstance().initWebDriver();
		webDriver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);//搜索元素時超時時間
		webDriver.manage().timeouts().setScriptTimeout(10, TimeUnit.SECONDS);//執行js腳本超時時間
		WebDriverWrapper realWebDriverWrapper = new WebDriverWrapperImpl(webDriver);
		
		InvocationHandler handler = new DynamicProxy(realWebDriverWrapper);
		webDriverWrapper = (WebDriverWrapper) Proxy.newProxyInstance(handler.getClass().getClassLoader(),
				realWebDriverWrapper.getClass().getInterfaces(), handler);//這裏使用代理,作用於下文解釋
	    WebDriverAdapter.setAdapter(webDriver);
	}
	//每個功能都要登錄才能操作,免登陸的用法還沒有實施。Cookie的用戶不起作用
	public void login() {
		webDriver.get(PageURL.LOGINPAGEURL);//將所有的URL 放在PageUrl類中進行管理。

		LoginPage loginPage = new LoginPage(webDriverWrapper);
		
		loginPage.setUsername("ksl");
		
		loginPage.setPassword("/ksl");
		
		loginPage.send();
	}
	
	public void destory() {
		webDriver.quit();
	}
}

接下來每個頁面測試繼承BaseTestPage即可:

package com.fujitsu.test.features;


import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import com.fujitsu.test.pages.LoginPage;
import com.fujitsu.test.pages.PageURL;

public class TestLoginPage extends BaseTestPage{
	

	@Before
	public void initWd() {
		super.init();
	}
	
	@Test
	public void testLoginCorrect() {
		webDriver.get(PageURL.LOGINPAGEURL);

		LoginPage loginPage = new LoginPage(webDriverWrapper);
		
		loginPage.setUsername("ksl");
		
		loginPage.setPassword("/ksl");
		
		loginPage.send();
		
	}
    
	@Test
	public void testLoginInCorrect() {
		webDriver.get(url);

		LoginPage loginPage = new LoginPage(webDriverWrapper);
		
		loginPage.setUsername("ksl");
		
		loginPage.setPassword("/ksl");
		
		loginPage.send();
		
	}
	
	
	
	@After
	public void destoryWd() {
		webDriver.quit();
	}
}


對於問題三,不可再每個操作前加上Thread.sleep()方法,加上一個動態代理即可:

package com.test.sahagin.util;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

import com.fujitsu.test.pages.PageURL;

public class DynamicProxy implements InvocationHandler {
	
	private Object subject;
	
	public DynamicProxy(Object subject) {
		super();
		this.subject = subject;
	}

	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		Thread.sleep(PageURL.SLEEPTIME);//每個方法執行前都會調用sleep方法。
		
		method.invoke(subject, args);
		return null;
	}
	
}

pom文件:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.fnst</groupId>
  <artifactId>test</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  
  <properties>  
	   <sahagin.version>0.9.2</sahagin.version>  
  </properties>
  
  <dependencies>
		<dependency>
			<groupId>org.seleniumhq.selenium</groupId>
			<artifactId>selenium-java</artifactId>
			<version>2.53.1</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-exec -->
		<dependency>
		    <groupId>org.apache.commons</groupId>
		    <artifactId>commons-exec</artifactId>
		    <version>1.3</version>
		</dependency>
		
		<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-nop -->
		<dependency>
		    <groupId>org.slf4j</groupId>
		    <artifactId>slf4j-nop</artifactId>
		    <version>1.7.23</version>
		</dependency>


		
		<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
		<dependency>
		    <groupId>commons-io</groupId>
		    <artifactId>commons-io</artifactId>
		    <version>2.4</version>
		</dependency>
		
		<dependency>
			<groupId>com.opera</groupId>
			<artifactId>operadriver</artifactId>
		</dependency>
		
		<dependency>  
	     <groupId>org.sahagin</groupId>    
	      <artifactId>sahagin</artifactId>    
	      <version>${sahagin.version}</version>   
	   </dependency>
	   
	   <dependency>
	   	<groupId>junit</groupId>
	   	<artifactId>junit</artifactId>
	   	<version>4.11</version>
	   	<scope>test</scope>
	   </dependency>  	
	   
	   <dependency>
		    <groupId>net.lightbody.bmp</groupId>
		    <artifactId>browsermob-core</artifactId>
		    <version>2.1.4</version>
        	<scope>test</scope>
		</dependency>
	   
</dependencies>
	<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>com.opera</groupId>
				<artifactId>operadriver</artifactId>
				<version>0.16</version>
				<exclusions>
					<exclusion>
						<groupId>org.seleniumhq.selenium</groupId>
						<artifactId>selenium-remote-driver</artifactId>
					</exclusion>
				</exclusions>
			</dependency>
		</dependencies>
	</dependencyManagement>
  
  
  <build>  
   <plugins>  
   	<plugin>   
   		<groupId>org.apache.maven.plugins</groupId>  
	    <artifactId>maven-compiler-plugin</artifactId>   
	    <version>2.5.1</version> 
	    <configuration>   
	        <source>1.7</source>   
	        <target>1.7</target>   
	        <encoding>UTF-8</encoding>   
	    </configuration>   
	</plugin>	
   		<plugin>   
		    <groupId>org.apache.maven.plugins</groupId>   
		    <artifactId>maven-resources-plugin</artifactId>   
		    <version>2.4</version>   
		    <configuration>   
		        <encoding>UTF-8</encoding>   
		    </configuration>   
		</plugin> 
     <plugin>  
       <groupId>org.apache.maven.plugins</groupId>  
       <artifactId>maven-surefire-plugin</artifactId>  
       <version>2.18 </version>  
       <configuration> 
       	  <forkCount>3</forkCount>
    	  <reuseForks>true</reuseForks>
          <argLine>  
           -javaagent:${settings.localRepository}/org/sahagin/sahagin/${sahagin.version}/sahagin-${sahagin.version}.jar  
          </argLine>  
          <useSystemClassLoader>true</useSystemClassLoader>
       </configuration>  
     </plugin>  
   </plugins>  
 </build>  
</project>



關於sahagin的使用見博客:http://blog.csdn.net/vichou_fa/article/details/54909812
  

                                                                                      

       關注微信公衆號每天學習一點程序員的職業經

                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章