最近空閒時間在探索Selenium的自動化測試,簡單的寫了一個小框架來測試公司的一個web產品。該框架包括如下模塊:html
1. Test case編寫模式(page模式,參考以前的博文http://www.cnblogs.com/AlwinXu/p/5537955.html)web
2. Test case的管理及執行 (主要是用nose)chrome
該模塊藉助了一個外部txt文件來記錄測試用例,每一個用例爲自身的文件名,若是不須要在本次執行,只需在文件名前添加一個「#」標識符就能夠跳過該用例的執行。shell
3. 測試報告的生成(xml和html兩種格式)app
對於自動化測試而言,這些模塊應該是最基本的配置了,固然還有一些輔助模塊好比日誌,其餘公共庫模塊等須要根據具體的業務逐漸豐富。閒話少說,用代碼交流吧。框架
該模塊用了Page模式,以前介紹過,此次只貼代碼了ide
BasePage.py:測試
__author__ = 'xua' #super class class BasePage(object): def __init__(self, driver): self.driver = driver
而後是各個web page繼承BasePage,LoginPage.py:url
from BasePage import BasePage from selenium.webdriver.common.by import By from selenium.webdriver.common.keys import Keys class LoginPage(BasePage): """description of class""" #page element identifier usename = (By.ID,'username') password = (By.ID, 'password') dialogTitle = (By.XPATH,'//html/body/div[7]/div/div/div[1]/h3') cancelButton = (By.XPATH,'//html/body/div[7]/div/div/div[3]/button[2]') #Get username textbox and input username def set_username(self,username): name = self.driver.find_element(*LoginPage.usename) name.send_keys(username) #Get password textbox and input password, then hit return def set_password(self, password): pwd = self.driver.find_element(*LoginPage.password) pwd.send_keys(password + Keys.RETURN) #Get pop up dialog title def get_DiaglogTitle(self): digTitle = self.driver.find_element(*LoginPage.dialogTitle) return digTitle.text #Get "cancel" button and then click def click_cancel(self): cancelbtn = self.driver.find_element(*LoginPage.cancelButton) cancelbtn.click()
測試用例信息類:spa
TestCaseInfo.py
class TestCaseInfo(object): """description of class""" def __init__(self, id="",name="",owner="",result="Failed",starttime="",endtime="",errorinfo=""): self.id = id self.name = name self.owner = owner self.result = result self.starttime = starttime self.endtime = endtime self.errorinfo = errorinfo
最後是每一個測試用例的編寫:(每一個用例必須有本身的用例信息,這裏有ID,Name等等信息,也會調用測試結果報告生成模塊來添加測試結果)
Test_Login.py
__author__ = 'xua' from selenium import webdriver from selenium.webdriver.common.keys import Keys from selenium.webdriver.common.alert import Alert import unittest import time from LoginPage import LoginPage from TestCaseInfo import TestCaseInfo from TestReport import TestReport class Test_Login(unittest.TestCase): #Setup def setUp(self): self.driver = webdriver.Chrome(r'C:\Users\xua\Downloads\chromedriver_win32\chromedriver.exe') self.driver.implicitly_wait(30) self.base_url = "http://10.222.30.145:9000/" #test case information self.testcaseinfo = TestCaseInfo(id="3",name="Login to floor manager lite using sbxadmin",owner="xua") self.testResult = TestReport() def test_Login(self): try: self.testcaseinfo.starttime = str(time.asctime()) #Step1: open base site self.driver.get(self.base_url) #Step2: Open Login page login_page = LoginPage(self.driver) #Step3: Enter username login_page.set_username("sbXadmin") #Step4: Enter password login_page.set_password("IGTtest1") #Checkpoint1: Check popup dialog title self.assertEqual(login_page.get_DiaglogTitle(),"Sign in","Not Equal") #Step5: Cancel dialog login_page.click_cancel() self.testcaseinfo.result = "Pass" except Exception as err: self.testcaseinfo.errorinfo = str(err) finally: self.testcaseinfo.endtime = str(time.asctime()) #tearDown def tearDown(self): self.driver.close() #write test result self.testResult.WriteHTML(self.testcaseinfo) if __name__ == "__main__": unittest.main()
1. 藉助外部文件記錄須要執行的用例
testcases.txt(帶「#」標識的用例不會被執行):
Test_Login.py
Test_Login_2.py
#Test_Login_3.py
Test_Login_4.py
2. 利用nose的nosetests命令執行各個用例:
import subprocess class RunTests(object): """description of class""" def __init__(self): self.testcaselistfile = "testcases.txt" #use nosetests command to execute test case list def LoadAndRunTestCases(self): f = open(self.testcaselistfile) testfiles = [test for test in f.readlines() if not test.startswith("#")] f.close() for item in testfiles: subprocess.call("nosetests "+str(item).replace("\\n",""),shell = True) if __name__ == "__main__": newrun = RunTests() newrun.LoadAndRunTestCases()
測試報表模塊寫了兩種格式:xml和html
TestReport.py
from xml.etree import ElementTree as ET import os import lxml.etree as mytree from lxml import html class TestReport(object): """description of class""" def __init__(self): self.testreport = "TestResult.xml" #If there is no "TestResult.xml", then create one def CreateTestResultFile(self): if os.path.exists(self.testreport) == False: newElem = ET.Element("TestCases") newTree = ET.ElementTree(newElem) newTree.write(self.testreport) #Write test result to xml def WriteResult(self,testcaseInfo): self.CreateTestResultFile() testResultFile = ET.parse(self.testreport) root = testResultFile.getroot() newElem = ET.Element("TestCase") newElem.attrib = { "ID":testcaseInfo.id, "Name":testcaseInfo.name, "Owner":testcaseInfo.owner, "Result":testcaseInfo.result, "StartTime":testcaseInfo.starttime, "EndTime":testcaseInfo.endtime, "ErrorInfo":testcaseInfo.errorinfo } root.append(newElem) testResultFile.write(self.testreport) #If there is no "TestResult.html" file exists, then create one with default style def CreateHtmlFile(self): if os.path.exists("TestResult.html") == False: f = open("TestResult.html",'w') message = """<html> <head> <title>Automation Test Result</title> <style> table { border-collapse: collapse; padding: 15px; font-family: "Trebuchet MS", Arial, Helvetica, sans-serif; } th{ background-color: green; color: white; border: 1px solid #ddd; padding-bottom: 15px; padding-top: 15px; } tr{ border: 1px solid #008000; padding-bottom: 8px; padding-top: 8px; text-align: left; } td{ border: 1px solid #008000; } </style> </head> <body> <h1>Automation Test Result</h1> <table> <tr> <th>ID</th> <th>Name</th> <th>Owner</th> <th>Result</th> <th>StartTime</th> <th>EndTime</th> <th>ErrorMessage</th> </tr> </table> </body> </html> """ f.write(message) f.close() #append new test result to testresult file def WriteHTML(self,testcaseinfo): self.CreateHtmlFile() f = open("TestResult.html","r") htmlcontent = f.read() f.close() tree = html.fromstring(htmlcontent) tableElem = tree.find(".//table") if testcaseinfo.result == "Failed": mytablerow = "<tr><td>{0}</td><td>{1}</td><td>{2}</td><td bgcolor=\"#FF0000\">{3}</td><td>{4}</td><td>{5}</td><td>{6}</td></tr>".format(testcaseinfo.id,testcaseinfo.name,testcaseinfo.owner,testcaseinfo.result,testcaseinfo.starttime,testcaseinfo.endtime,testcaseinfo.errorinfo) else: mytablerow = "<tr><td>{0}</td><td>{1}</td><td>{2}</td><td>{3}</td><td>{4}</td><td>{5}</td><td>{6}</td></tr>".format(testcaseinfo.id,testcaseinfo.name,testcaseinfo.owner,testcaseinfo.result,testcaseinfo.starttime,testcaseinfo.endtime,testcaseinfo.errorinfo) tableElem.append(mytree.HTML(str(mytablerow))) f = open("TestResult.html","w") #html.tostring newContent = repr(html.tostring(tree,method="html",with_tail=False)) newContent = newContent.replace(r"\n","").replace(r"\t","").replace('b\'',"") newContent = newContent[:len(newContent)-1] f.write(newContent) f.close()
ok,最後看一下生成的測試報表:
在網上有不少關於Selenium自動化的Best Practice,固然你們也能夠根據本身的需求來DIY本身的框架,無論簡陋與否,好用纔是硬道理:)!