這套框架適合使用的場景:
1、測試資料不多
2、執行人員不需要會程式碼
3、看報告的時候要看執行詳細結果
工程分為以下幾部分:
1、公用方法包-Util
2、需要呼叫的固定變數包-ProjectVar
3、元素路徑目錄-Conf
4、頁面元素常用動作方法+模組動作方法包-Action
5、測試用例執行包-TestUnittest
6、截圖目錄
看一下目錄組成結構:
這裡寫圖片描述

  • 1.公用方法包-Util
  • 1.1 DirAndFile.py
  • 這個模組是為了建立目錄用的
#encoding=utf-8
import os
from ProjectVar.Var import *

def createDir(path,dirName):
    #os.path.join(x,y)是拼接路徑用的
    dirPath=os.path.join(path,dirName)
    #判斷路徑是否存在,存在則pass,否則新建
    if os.path.exists(dirPath):
        return dirPath
        pass
    else:
        os.mkdir(dirPath)
        return dirPath

  • 1.2Excel.py
  • 這個模組封裝了excel的常用操作方法
#encoding=utf-8
from openpyxl import Workbook
from openpyxl import load_workbook
from ProjectVar.Var import *
from openpyxl.styles import Border,Side,Font

class Excel(object):
    def __init__(self):
        self.font=Font(color=None)
        self.colorDict={'red':'FFFF3030','green':'FF008B00'}
        self.wb=load_workbook(test_path)
        self.ws=self.wb.active

    def rename(self,new_name):
        #給表格重新命名
        self.ws.title=new_name
        self.wb.save(test_path)

    def GetSheetName(self):
        #獲取所有表格名稱
        return self.wb.get_sheet_names()

    def GetSheetByName(self,sheet_name):
        #通過表格名稱獲取表格
        self.ws=self.wb.get_sheet_by_name(sheet_name)
        return self.ws

    def GetCurrentSheetName(self):
        #獲取當前表格名稱
        return self.ws.title

    def GetCellContent(self,row_num,col_num):
        #獲取單元格內容
        return self.ws.cell(row=row_num,column=col_num).value

    def WriteCellContent(self,row_num,col_num,content):
        #往指定的單元格里面寫入內容
        self.ws.cell(row=row_num,column=col_num).value=content
        self.wb.save(test_path)

    def GetMaxRow(self):
        #獲取最大行號
        return self.ws.max_row

    def GetMaxColumn(self):
        #獲取最大列號
        return self.ws.max_column

其實本次框架中沒有用到excel,但是我還是把他寫上,方便大家使用;【對於資料的傳遞也可以使用excel來操作的】

  • 1.3GetConf.py
  • 這個模組是為了操作配置檔案用的方法
#encoding=utf-8
import ConfigParser
from ProjectVar.Var import *

class ParsePageObjectRepositoryConfig(object):
    def __init__(self):
        self.cf=ConfigParser.ConfigParser()
        self.cf.read(page_object_repository_path)

    def getItemsFromSection(self,sectionName):
        items=self.cf.items(sectionName)
        return dict(items)

if __name__=='__main__':
    #除錯程式碼
    p=ParsePageObjectRepositoryConfig()
    print p.getItemsFromSection('126mail_login')
    print p.getItemsFromSection('126mail_login')['loginpage.frame'].split('//')[1]
    print type(p.getItemsFromSection('126mail_login')['loginpage.frame'].split('//')[1])
  • 1.4log.py
  • 列印日誌用的(這裡可以不用這個,因為HTML就可以用)
#encoding=utf-8

import logging
import logging.config
from ProjectVar.Var import *
import os


#讀取日誌的配置檔案
logging.config.fileConfig(project_path+'\\Conf\\Logger.conf')
#選擇一個日誌格式
logger=logging.getLogger('example02')

def warning(message):
    #列印warning級別的資訊(日誌級別較弱,最弱的是debug)
    logger.warn(message)

def debug(message):
    #列印debug級別的資訊(日誌資訊級別最弱
    logger.debug(message)

def info(message):
    #列印info級別資訊
    logger.info(message)

def error(message):
    #列印wornging級別資訊
    logger.error(message)


if __name__=='__main__':
    a = project_path + '\\Conf\\Logger.conf'
    print os.path.exists(a)
    print a
    logging.config.fileConfig(project_path + '\\Conf\\Logger.conf')
    info('info level')
    warning('warning level')
    error('error level')
    debug('debug level')
  • 1.5ObjectMap.py
  • 這個模組是獲取頁面元素的方法,直接返回要操作的元素,後面呼叫的時候只需要傳遞定位元素方法和路徑就可以。
#encoding=utf-8
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support.ui import Select
import time

def getElement(driver,locateType,locateExpression):
    #獲取頁面單個元素
    try:
        wait=WebDriverWait(driver,10)
        return wait.until(lambda x:x.find_element(locateType,locateExpression))
    except Exception,e:
        raise e

def getElements(driver,locateType,locateExpression):
    #獲取頁面多個元素
    try:
        wait=WebDriverWait(driver,10)
        return wait.until(lambda x:x.find_elements(locateType,locateExpression))
    except Exception,e:
        raise e

def getSelectElementWithIndex(driver,index_num):
    #獲取select下拉框元素---index
    select_element=Select(driver.find_element_by_xpath('//select'))
    #列印已選中的文字
    print select_element.all_selected_options[0].text
    return select_element.select_by_index(index_num)

def getSelectElementWithText(driver,text):
    #獲取select下拉框元素----text
    select_element=Select(driver.find_element_by_xpath('//select'))
    #列印已選中的文字
    print select_element.all_selected_options[0].text
    return select_element.select_by_visible_text(text)

def getSelectElementWithValue(driver,value):
    #獲取select下拉框元素---value
    select_element=Select(driver.find_element_by_xpath('select'))
    #列印已選中的文字
    print select_element.all_selected_options[0].text
    return select_element.select_by_value(value)
  • 2 .需要呼叫的公共變數包-ProjectVar
  • 2.1Var.py
  • 這個模組裡面是程式碼中用到的公用已知變數
#encoding=utf-8
import os
import time

#當前檔案路徑
file_path=__file__
#工程路徑
#os.path.dirname(__file__)當前檔案所在路徑
project_path=os.path.dirname(os.path.dirname(__file__)).decode('utf-8')

page_object_repository_path=project_path+'//Conf//PageObjectRepository .ini'

url='http:\\www.126.com'

chrom="c:\\Python27\\chromedriver"
ie="c:\\Python27\\IEDriverServer"
firefox="c:\\Python27\\geckodriver"
  • 3 . 元素路徑目錄-Conf
  • 3.1PageObjectRepository .ini
  • 裡面都是頁面元素路徑的配置檔案
[configparse操作配置檔案的時候有坑]
[ini中的內容要全部小寫,否則讀取出來的時候會自動轉換成小寫,這樣就會發生匹配不上的情況]

[126mail_login]
loginpage.frame=xpath>//iframe[@id='x-URS-iframe']
loginpage.username=xpath>//span[.='@126.com']//preceding-sibling::input
loginpage.password=xpath>//label[.='密碼']//following-sibling::input[2]
loginpage.loginbutton=xpath>//a[@id='dologin']

[126mail_homepage]
home_age.addressbook=xpath>//div[text()='通訊錄']

[126mail_addcontactspage]
addcontacts_page.create_contacts_btn=xpath>//header/div[@role='toolbar']/div[@class='nui-toolbar-item'][1]
addcontacts_page.contact_person_name=xpath>//a[@title='編輯詳細姓名']/preceding-sibling::div/input
addcontacts_page.contact_person_email=xpath>//*[@id='iaddress_MAIL_wrap']//input
addcontacts_page.star_contacts=xpath>//span[text()='設為星標聯絡人']/preceding-sibling::span/b
addcontacts_page.contact_person_mobile=xpath>//*[@id='iaddress_TEL_wrap']//dd//input
addcontacts_page.contact_person_comment=xpath>//textarea
addcontacts_page.save_contace_person=xpath>//span[.='確 定']
  • 4 .頁面元素常用動作方法+模組動作方法包-Action
  • 4.1basic_function.py
  • 這個模組裡面寫的是頁面操作的常用方法
#encoding=utf-8
from selenium import webdriver
from Util.ObjectMap import *
from ProjectVar.Var import *
from Util.DirAndFile import *
import traceback
import os

def open_browser(browserName,*arg):
    #開啟瀏覽器
    try:
        if browserName.lower()=='ie':
            driver=webdriver.Ie(executable_path=ie)
            return driver
        elif browserName.lower()=='chrome':
            driver=webdriver.Chrome(executable_path=chrom)
            return driver
        elif browserName.lower()=='firefox':
            driver=webdriver.Firefox(executable_path=firefox)
            return driver
        else:
            print u"has no such browser"
        pass
    except Exception,e:
        raise e

def visit_url(driver,url,*arg):
    #訪問網頁
    try:
        driver.get(url)
    except Exception,e:
        raise e

def close_browser(driver):
    #退出瀏覽器
    try:
        driver.quit()
    except Exception,e:
        raise e

def enter_frame(driver,locatorType,locatorExpression,*arg):
    #切換frame
    try:
        driver.switch_to.frame(getElement(driver,locatorType,locatorExpression))
    except Exception,e:
        raise e

def get_out_frame(driver):
    #切出來 frame
    try:
        driver.switch_to_default_content()
    except Exception,e:
        raise e

def input_string(driver,locatorType,locatorExpression,content,*arg):
    #send_keys and clear
    try:
        getElement(driver, locatorType, locatorExpression).clear()
        pause(0.5)
        getElement(driver,locatorType,locatorExpression).send_keys(content)
        pause(0.5)
    except Exception,e:
        raise e


def click_button(driver,locatorType,locatorExpression):
    #點選操作
    try:
        getElement(driver, locatorType, locatorExpression).click()
    except Exception,e:
        raise e

def assert_keyword(driver,excepted_word,*arg):
    #斷言
    try:
        assert True==(excepted_word in driver.page_source)
    except AssertionError,e:
        raise e
    except Exception,e:
        raise e
    else:
        print 'keyword : %s in page_source'%excepted_word


def pause(seconds,*arg):
    time.sleep(float(seconds))


def max_window(driver):
    #最大化視窗
    try:
        driver.maximize_window()
    except Exception,e:
        raise e


def get_element_out_to_can_see(driver,locatorType, locatorExpression,*arg):
    #把元素拉倒可見的位置
    try:
        target = getElement(driver,locatorType, locatorExpression)
        driver.execute_script("arguments[0].scrollIntoView();", target)
    except Exception,e:
        raise e


def scroll_page_to_buttom(driver):
    #滾動條到最下方
    try:
        driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
    except Exception,e:
        raise e


def scroll_page_to_top(driver):
    #滾動條到最上方
    try:
        driver.execute_script("window.scrollTo(0, 0);")
    except Exception,e:
        raise e


def capture_screen(driver,pictureName):
    # 獲取正常截圖
    dirPath=createDir(project_path+"//ScreenPictures//CapturePicture",time.strftime("%Y-%m-%d"))
    os.chdir(dirPath)
    try:
        driver.get_screenshot_as_file(pictureName)
    except Exception,e:
        raise e

def error_screen(driver,pictureName):
    # 獲取異常截圖
    dirPath=createDir(project_path + "//ScreenPictures//ErrorPicture", time.strftime("%Y-%m-%d"))
    os.chdir(dirPath)
    try:
        driver.get_screenshot_as_file(pictureName)
    except Exception,e:
        raise e
  • 4.2 action_login.py
  • 這個模組中寫的是login的操作步驟方法
#encoding=utf-8
from Action.basic_function import *

def login(driver,usernameAndpassword,*arg):
    username,password=usernameAndpassword.split('||')
    visit_url(driver,url)
    pause(2)
    enter_frame(driver,"id", "x-URS-iframe")
    pause(1)
    input_string(driver,"xpath", "//span[.='@126.com']//preceding-sibling::input", username)
    pause(1)
    input_string(driver,"xpath", "//label[.='密碼']//following-sibling::input[2]", password)
    pause(1)
    click_button(driver,"xpath", "//a[@id='dologin']")
  • 4.3 action_addaddress.py
  • 這個模組裡面封裝的是新增聯絡人的動作步驟
#encoding=utf-8
from Action.basic_function import *

driver=None

def add_address(driver,name,email,tel,comment,*arg):
    click_button(driver,"xpath","//div[text()='通訊錄']")
    pause(2)
    click_button(driver,"xpath","//header/div[@role='toolbar']/div[@class='nui-toolbar-item'][1]")
    pause(2)
    input_string(driver,"xpath","//a[@title='編輯詳細姓名']/preceding-sibling::div/input",name)
    pause(0.5)
    input_string(driver,"xpath","//*[@id='iaddress_MAIL_wrap']//input",email)
    pause(0.5)
    input_string(driver,"xpath","//*[@id='iaddress_TEL_wrap']//dd//input",tel)
    pause(0.5)
    input_string(driver,"xpath","//textarea",comment)
    pause(0.5)
    click_button(driver,"xpath","//span[.='確 定']")
  • 4.4 test_data.py
  • 這個模組裡面寫的是用到的測試資料(所有用到的測試資料全在裡面,和程式碼是完全分離的)
#encoding=utf-8
#login的測試資料
login_info=("lxxxx_xxxx||ainixxxxxxxxx","lxxxx_xxxx||ainixxxxxxx")
#login後的斷言內容
login_keyword=u'退出'
#新增聯絡人測試資料
addressbook_info=[('ajin','[email protected]','18681867102','I am a beautiful girl ,I love my dad and mum!'),
                  ('gangbeng','[email protected]','18689856963','I like meat !')]
#瀏覽器的選擇
browser_name='Chrome'
  • 5 .測試用例執行包-TestUnittest
  • 5.1 login_unittest.py
#encoding=utf-8
from HTMLTestRunner import HTMLTestRunner
import unittest
from Action.action_login import *
from Action.test_data import *

class TestLogin(unittest.TestCase):
    def setUp(self):
        self.driver=open_browser(browser_name)

    def test_login(self):
        for i in range(len(login_info)):
            try:
                login(self.driver,login_info[i])
                pause(3)
                self.assertIn(login_keyword,self.driver.page_source,login_keyword+' not in page_source')
            except Exception,e:
                print 'login error, ' + login_keyword + 'in page_source can not be found !'
                error_screen(self.driver,'login-'+login_keyword+time.strftime('%H%M%S')+'.png')
                print traceback.format_exc()
            else:
                capture_screen(self.driver,'login-'+login_keyword+time.strftime('%H%M%S')+'.png')
                print 'login success, '+login_keyword+'in page_source can be found !'
            finally:
                print u'login 第%d次用例執行結束'%(i+1)
            pause(2)

    def tearDown(self):
        self.driver.quit()

if __name__=='__main__':
    suite=unittest.TestSuite()
    suite.addTest(TestLogin('test_login'))
    with open('HTMLForLogin.html','w')as fp:
        runner=HTMLTestRunner(stream=fp,title='login report',description='report',verbosity=2)
        runner.run(suite)
  • 5.2 addaddress_unittest.py
  • 增加聯絡人測試執行模組
#encoding=utf-8
from HTMLTestRunner import HTMLTestRunner
import unittest
from Action.action_addaddress import *
from Action.action_login import *
from Action.test_data import *
from Action.test_data import *

class TestAddAdress(unittest.TestCase):
    def setUp(self):
        self.driver=open_browser(browser_name)

    def test_addAddress(self):
        try:
            login(self.driver, login_info[0])
            pause(2)
        except Exception,e:
            raise e
        else:
            print 'login success'
        finally:
            print 'next is addaddressbook'

        for i in range(len(addressbook_info)):
            try:
                add_address(self.driver,addressbook_info[i][0],addressbook_info[i][1],addressbook_info[i][2],addressbook_info[i][3])
                pause(2)
                self.assertIn(addressbook_info[i][0],self.driver.page_source,addressbook_info[i][0]+'not in page_source')
            except Exception,e:
                print 'addaddress error, ' + addressbook_info[i][0] + 'in page_source can not be found !'
                error_screen(self.driver,'addressbook-'+addressbook_info[i][0]+time.strftime('%H%M%S')+'.png')
                print traceback.format_exc()
            else:
                capture_screen(self.driver,'addressbook-'+addressbook_info[i][0]+time.strftime('%H%M%S')+'.png')
                print 'addaddress success, '+addressbook_info[i][0]+'in page_source can be found !'
            finally:
                print u'addaddress 第%d次用例執行結束'%(i+1)
            pause(2)
            continue


    def tearDown(self):
        self.driver.quit()

if __name__=='__main__':
    suite=unittest.TestSuite()
    suite.addTest(TestAddAdress('test_addAddress'))
    with open('HTMLForAddAddress.html','w')as fp:
        runner=HTMLTestRunner(stream=fp,title='addAddress report',description='report',verbosity=2)
        runner.run(suite)

我這裡沒有再開一個模組,來專門的用unittest去整合他們,大家可以自己操作一下,很簡單的!!
之前的1、2、3、4都是為了5的執行,將5中的兩個測試指令碼跑完之後,得到測試截圖和測試報告:
這裡寫圖片描述

這裡寫圖片描述

以上的例子是用126郵箱登入建立聯絡人做的測試框架,同樣的,在我們的專案中我也用了,還挺好用的,畢竟測試資料不多,這樣寫夠了,但是覺得還是要改進下,後面改進了,會繼續更新!!!
這裡寫圖片描述

.