selenium-python-unittest自动化测试框架(数据和代码完全分离)

这套框架适合使用的场景:
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邮箱登录创建联系人做的测试框架,同样的,在我们的项目中我也用了,还挺好用的,毕竟测试数据不多,这样写够了,但是觉得还是要改进下,后面改进了,会继续更新!!!
这里写图片描述

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