51Testing软件测试论坛

标题: 【转】简易selenium自动化测试框架(Python) [打印本页]

作者: lsekfe    时间: 2016-9-13 11:34
标题: 【转】简易selenium自动化测试框架(Python)
转自:博客园
最近空闲时间在探索Selenium的自动化测试,简单的写了一个小框架来测试公司的一个web产品。该框架包括以下模块:
1. Test case编写模式(page模式,参考之前的博文http://www.cnblogs.com/AlwinXu/p/5537955.html)
2. Test case的管理及执行 (主要是用nose)
  该模块借助了一个外部txt文件来记录测试用例,每个用例为自身的文件名,如果不需要在本次执行,只需在文件名前添加一个“#”标识符就可以跳过该用例的执行。
3. 测试报告的生成(xml和html两种格式)

对于自动化测试而言,这些模块应该是最基本的配置了,当然还有一些辅助模块比如日志,其他公共库模块等需要根据具体的业务逐渐丰富。闲话少说,用代码交流吧。
测试用例编写
该模块用了Page模式,之前介绍过,这次只贴代码了
BasePage.py:
  1. __author__ = 'xua'

  2. #super class
  3. class BasePage(object):
  4.     def __init__(self, driver):
  5.         self.driver = driver
复制代码
然后是各个web page继承BasePage,LoginPage.py:
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()
测试用例信息类:
TestCaseInfo.py
  1. class TestCaseInfo(object):
  2.     """description of class"""

  3.     def __init__(self, id="",name="",owner="",result="Failed",starttime="",endtime="",errorinfo=""):
  4.         self.id = id
  5.         self.name = name
  6.         self.owner = owner
  7.         self.result = result
  8.         self.starttime = starttime
  9.         self.endtime = endtime
  10.         self.errorinfo = errorinfo
复制代码
最后是每个测试用例的编写:(每个用例必须有自己的用例信息,这里有ID,Name等等信息,也会调用测试结果报告生成模块来添加测试结果)
Test_Login.py
  1. __author__ = 'xua'

  2. from selenium import webdriver
  3. from selenium.webdriver.common.keys import Keys
  4. from selenium.webdriver.common.alert import Alert
  5. import unittest
  6. import time
  7. from LoginPage import LoginPage
  8. from TestCaseInfo import TestCaseInfo
  9. from TestReport import TestReport

  10. class Test_Login(unittest.TestCase):

  11.     #Setup
  12.     def setUp(self):
  13.         self.driver = webdriver.Chrome(r'C:\Users\xua\Downloads\chromedriver_win32\chromedriver.exe')
  14.         self.driver.implicitly_wait(30)
  15.         self.base_url = "http://10.222.30.145:9000/"
  16.         #test case information
  17.         self.testcaseinfo = TestCaseInfo(id="3",name="Login to floor manager lite using sbxadmin",owner="xua")
  18.         self.testResult = TestReport()
  19.   
  20.     def test_Login(self):
  21.         try:
  22.             self.testcaseinfo.starttime = str(time.asctime())
  23.             #Step1: open base site
  24.             self.driver.get(self.base_url)
  25.             #Step2: Open Login page
  26.             login_page = LoginPage(self.driver)
  27.             #Step3: Enter username
  28.             login_page.set_username("sbXadmin")
  29.             #Step4: Enter password
  30.             login_page.set_password("IGTtest1")
  31.             #Checkpoint1: Check popup dialog title
  32.             self.assertEqual(login_page.get_DiaglogTitle(),"Sign in","Not Equal")
  33.             #Step5: Cancel dialog
  34.             login_page.click_cancel()
  35.             self.testcaseinfo.result = "Pass"
  36.         except Exception as err:
  37.             self.testcaseinfo.errorinfo = str(err)
  38.         finally:
  39.             self.testcaseinfo.endtime = str(time.asctime())

  40.     #tearDown
  41.     def tearDown(self):
  42.         self.driver.close()
  43.         #write test result
  44.         self.testResult.WriteHTML(self.testcaseinfo)

  45. if __name__ == "__main__":
  46.     unittest.main()
复制代码
用例执行模块
1. 借助外部文件记录需要执行的用例
testcases.txt(带“#”标识的用例不会被执行):
  1. Test_Login.py
  2. Test_Login_2.py
  3. #Test_Login_3.py
  4. Test_Login_4.py
复制代码
2. 利用nose的nosetests命令执行各个用例:
  1. import subprocess

  2. class RunTests(object):
  3.     """description of class"""
  4.     def __init__(self):
  5.         self.testcaselistfile = "testcases.txt"
  6.    
  7.     #use nosetests command to execute test case list
  8.     def LoadAndRunTestCases(self):
  9.         f = open(self.testcaselistfile)
  10.         testfiles = [test for test in f.readlines() if not test.startswith("#")]
  11.         f.close()
  12.         for item in testfiles:
  13.             subprocess.call("nosetests "+str(item).replace("\\n",""),shell = True)

  14. if __name__ == "__main__":
  15.     newrun = RunTests()
  16.     newrun.LoadAndRunTestCases()
复制代码
测试结果报表生成模块
测试报表模块写了两种格式:xml和html
TestReport.py
  1. from xml.etree import ElementTree as ET
  2. import os
  3. import lxml.etree as mytree
  4. from lxml import html

  5. class TestReport(object):
  6.     """description of class"""
  7.     def __init__(self):
  8.         self.testreport = "TestResult.xml"

  9.     #If there is no "TestResult.xml", then create one
  10.     def CreateTestResultFile(self):
  11.         if os.path.exists(self.testreport) == False:
  12.             newElem = ET.Element("TestCases")
  13.             newTree = ET.ElementTree(newElem)
  14.             newTree.write(self.testreport)
  15.                         
  16.     #Write test result to xml
  17.     def WriteResult(self,testcaseInfo):
  18.         self.CreateTestResultFile()
  19.         testResultFile = ET.parse(self.testreport)
  20.         root = testResultFile.getroot()
  21.         newElem = ET.Element("TestCase")
  22.         newElem.attrib = {
  23.             "ID":testcaseInfo.id,
  24.             "Name":testcaseInfo.name,
  25.             "Owner":testcaseInfo.owner,
  26.             "Result":testcaseInfo.result,
  27.             "StartTime":testcaseInfo.starttime,
  28.             "EndTime":testcaseInfo.endtime,
  29.             "ErrorInfo":testcaseInfo.errorinfo
  30.             }
  31.         root.append(newElem)

  32.         testResultFile.write(self.testreport)

  33.     #If there is no "TestResult.html" file exists, then create one with default style
  34.     def CreateHtmlFile(self):
  35.         if os.path.exists("TestResult.html") == False:
  36.             f = open("TestResult.html",'w')
  37.             message = """<html>
  38.             <head>   
  39.                 <title>Automation Test Result</title>
  40.                 <style>
  41.                     table {
  42.                             border-collapse: collapse;
  43.                             padding: 15px;
  44.                             font-family: "Trebuchet MS", Arial, Helvetica, sans-serif;
  45.                             }
  46.                     th{
  47.                         background-color: green;
  48.                         color: white;
  49.                         border: 1px solid #ddd;
  50.                         padding-bottom: 15px;
  51.                         padding-top: 15px;
  52.                     }
  53.                     tr{
  54.                         border: 1px solid #008000;
  55.                         padding-bottom: 8px;
  56.                         padding-top: 8px;
  57.                         text-align: left;
  58.                     }
  59.                     td{
  60.                         border: 1px solid #008000;
  61.                     }
  62.                 </style>
  63.             </head>
  64.             <body>
  65.                 <h1>Automation Test Result</h1>
  66.                 <table>
  67.                     <tr>
  68.                         <th>ID</th>
  69.                         <th>Name</th>
  70.                         <th>Owner</th>
  71.                         <th>Result</th>
  72.                         <th>StartTime</th>
  73.                         <th>EndTime</th>
  74.                         <th>ErrorMessage</th>
  75.                    </tr>
  76.                 </table>
  77.             </body>
  78.             </html>
  79.             """
  80.             f.write(message)
  81.             f.close()

  82.     #append new test result to testresult file
  83.     def WriteHTML(self,testcaseinfo):

  84.         self.CreateHtmlFile()

  85.         f = open("TestResult.html","r")
  86.         
  87.         htmlcontent = f.read()
  88.         f.close()
  89.         tree = html.fromstring(htmlcontent)
  90.         tableElem = tree.find(".//table")
  91.         if testcaseinfo.result == "Failed":
  92.             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)
  93.         else:
  94.             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)
  95.         tableElem.append(mytree.HTML(str(mytablerow)))

  96.         f = open("TestResult.html","w")
  97.         #html.tostring
  98.         newContent = repr(html.tostring(tree,method="html",with_tail=False))
  99.         newContent = newContent.replace(r"\n","").replace(r"\t","").replace('b\'',"")
  100.         newContent = newContent[:len(newContent)-1]
  101.         f.write(newContent)
  102.         f.close()
复制代码
ok,最后看一下生成的测试报表:

总结
在网上有很多关于Selenium自动化的Best Practice,当然大家也可以根据自己的需求来DIY自己的框架,不管简陋与否,好用才是硬道理!


作者: SunnyLan    时间: 2016-9-13 15:37
这例子看起来不错




欢迎光临 51Testing软件测试论坛 (http://bbs.51testing.com/) Powered by Discuz! X3.2