Python+unittest UI自动化

前言:此代码,网上实例+同事提供思路+自己编码,100%手工完成,希望能认识更多的同道中人,一起探讨。

已下是简单介绍(未开源代码),有兴趣的朋友网上教程深入学习。

一.相关软件工具支撑。

python3+selenium库+unittest框架+CI封装,编写的 业务模块分离,数据分离,元素分离,自动化脚本。

1.python3+pycharm:安装比较简单,参照如下:

https://www.runoob.com/python3/python3-install.html

2.selenium库

自动化的原理实现主依靠selenium工具。

selenium 是一个用于Web应用程序测试的工具。Selenium测试直接运行在浏览器中,就像真正的用户在操作一样。支持的浏览器包括IE(7, 8, 9, 10, 11),Mozilla Firefox,Safari,Google Chrome,Opera等。这个工具的主要功能包括:测试与浏览器的兼容性——测试你的应用程序看是否能够很好得工作在不同浏览器和操作系统之上。测试系统功能——创建回归测试检验软件功能和用户需求。支持自动录制动作和自动生成 .Net、Java、Perl等不同语言的测试脚本。selenium也可以用于爬虫等其他。

selenium安装:

个人建议在线安装,先安装pip教程:https://www.jianshu.com/p/856bf8ff130d

在Scripts文件夹内(如上图),shift+鼠标右键,然后输入python -m pip install selenium指令。

安装是否成功输入如下命令:

到这里,selenium已经安装好了

3.浏览器驱动安装。

点击下载chrome的webdriver:http://chromedriver.storage.googleapis.com/index.html

1.驱动下载完成,解压。

2.将解压后文件chromedriver.exe复制到python的Scripts安装目录下(上面已添加此步骤可以忽略),并且添加到path环境变量。

3.将目录chrome的安装目录添加到path环境变量。

4.运行下面代码:成功打开百度即为成功:

        from selenium import webdriver

        driver = webdriver.Chrome()     

  driver.get('http://www.baidu.com')

二,代码部分。

unittest框架,参考:https://www.cnblogs.com/yufeihlf/p/5707929.html

unittest单元测试框架不仅可以适用于单元测试,还可以适用WEB自动化测试用例的开发与执行,该测试框架可组织执行测试用例,并且提供了丰富的断言方法,判断测试用例是否通过,最终生成测试结果。今天笔者就总结下如何使用unittest单元测试框架来进行WEB自动化测试。

目录

一、unittest模块的各个属性说明

二、使用unittest框架编写测试用例思路

三、使用unittest框架编写测试用例实例

一、unittest模块的各个属性说明

点击返回目录

    先来聊一聊unittest模块的各个属性,所谓知己知彼方能百战百胜,了解unittest的各个属性,对于后续编写用例有很大的帮助。

1.unittest的属性如下:

['BaseTestSuite', 'FunctionTestCase', 'SkipTest', 'TestCase', 'TestLoader', 'TestProgram', 'TestResult', 'TestSuite', 'TextTestResult', 'TextTestRunner', '_TextTestResult', '__all__', '__builtins__', '__doc__', '__file__', '__name__', '__package__', '__path__', '__unittest', 'case', 'defaultTestLoader', 'expectedFailure', 'findTestCases', 'getTestCaseNames', 'installHandler', 'loader', 'main', 'makeSuite', 'registerResult', 'removeHandler', 'removeResult', 'result', 'runner', 'signals', 'skip', 'skipIf', 'skipUnless', 'suite', 'util']

说明:

unittest.TestCase:TestCase类,所有测试用例类继承的基本类。

classBaiduTest(unittest.TestCase):

unittest.main():使用她可以方便的将一个单元测试模块变为可直接运行的测试脚本,main()方法使用TestLoader类来搜索所有包含在该模块中以“test”命名开头的测试方法,并自动执行他们。执行方法的默认顺序是:根据ASCII码的顺序加载测试用例,数字与字母的顺序为:0-9,A-Z,a-z。所以以A开头的测试用例方法会优先执行,以a开头会后执行。

unittest.TestSuite():unittest框架的TestSuite()类是用来创建测试套件的。

unittest.TextTextRunner():unittest框架的TextTextRunner()类,通过该类下面的run()方法来运行suite所组装的测试用例,入参为suite测试套件。

unittest.defaultTestLoader(): defaultTestLoader()类,通过该类下面的discover()方法可自动更具测试目录start_dir匹配查找测试用例文件(test*.py),并将查找到的测试用例组装到测试套件,因此可以直接通过run()方法执行discover。用法如下:

discover=unittest.defaultTestLoader.discover(test_dir, pattern='test_*.py')

unittest.skip():装饰器,当运行用例时,有些用例可能不想执行等,可用装饰器暂时屏蔽该条测试用例。一种常见的用法就是比如说想调试某一个测试用例,想先屏蔽其他用例就可以用装饰器屏蔽。

@unittest.skip(reason): skip(reason)装饰器:无条件跳过装饰的测试,并说明跳过测试的原因。

@unittest.skipIf(reason): skipIf(condition,reason)装饰器:条件为真时,跳过装饰的测试,并说明跳过测试的原因。

@unittest.skipUnless(reason): skipUnless(condition,reason)装饰器:条件为假时,跳过装饰的测试,并说明跳过测试的原因。

@unittest.expectedFailure(): expectedFailure()测试标记为失败。

2.TestCase类的属性如下:

['__call__', '__class__', '__delattr__', '__dict__', '__doc__', '__eq__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_addSkip', '_baseAssertEqual', '_classSetupFailed', '_deprecate', '_diffThreshold', '_formatMessage', '_getAssertEqualityFunc', '_truncateMessage', 'addCleanup', 'addTypeEqualityFunc', 'assertAlmostEqual', 'assertAlmostEquals', 'assertDictContainsSubset', 'assertDictEqual', 'assertEqual', 'assertEquals', 'assertFalse', 'assertGreater', 'assertGreaterEqual', 'assertIn', 'assertIs', 'assertIsInstance', 'assertIsNone', 'assertIsNot', 'assertIsNotNone', 'assertItemsEqual', 'assertLess', 'assertLessEqual', 'assertListEqual', 'assertMultiLineEqual', 'assertNotAlmostEqual', 'assertNotAlmostEquals', 'assertNotEqual', 'assertNotEquals', 'assertNotIn', 'assertNotIsInstance', 'assertNotRegexpMatches', 'assertRaises', 'assertRaisesRegexp', 'assertRegexpMatches', 'assertSequenceEqual', 'assertSetEqual', 'assertTrue', 'assertTupleEqual', 'assert_', 'countTestCases', 'debug', 'defaultTestResult', 'doCleanups', 'fail', 'failIf', 'failIfAlmostEqual', 'failIfEqual', 'failUnless', 'failUnlessAlmostEqual', 'failUnlessEqual', 'failUnlessRaises', 'failureException', 'id', 'longMessage', 'maxDiff', 'run', 'setUp', 'setUpClass', 'shortDescription', 'skipTest', 'tearDown', 'tearDownClass']

说明:

setUp():setUp()方法用于测试用例执行前的初始化工作。如测试用例中需要访问数据库,可以在setUp中建立数据库连接并进行初始化。如测试用例需要登录web,可以先实例化浏览器。

tearDown():tearDown()方法用于测试用例执行之后的善后工作。如关闭数据库连接。关闭浏览器。

assert*():一些断言方法:在执行测试用例的过程中,最终用例是否执行通过,是通过判断测试得到的实际结果和预期结果是否相等决定的。

assertEqual(a,b,[msg='测试失败时打印的信息']):断言a和b是否相等,相等则测试用例通过。

assertNotEqual(a,b,[msg='测试失败时打印的信息']):断言a和b是否相等,不相等则测试用例通过。

assertTrue(x,[msg='测试失败时打印的信息']):断言x是否True,是True则测试用例通过。

assertFalse(x,[msg='测试失败时打印的信息']):断言x是否False,是False则测试用例通过。

assertIs(a,b,[msg='测试失败时打印的信息']):断言a是否是b,是则测试用例通过。

assertNotIs(a,b,[msg='测试失败时打印的信息']):断言a是否是b,不是则测试用例通过。

assertIsNone(x,[msg='测试失败时打印的信息']):断言x是否None,是None则测试用例通过。

assertIsNotNone(x,[msg='测试失败时打印的信息']):断言x是否None,不是None则测试用例通过。

assertIn(a,b,[msg='测试失败时打印的信息']):断言a是否在b中,在b中则测试用例通过。

assertNotIn(a,b,[msg='测试失败时打印的信息']):断言a是否在b中,不在b中则测试用例通过。

assertIsInstance(a,b,[msg='测试失败时打印的信息']):断言a是是b的一个实例,是则测试用例通过。

assertNotIsInstance(a,b,[msg='测试失败时打印的信息']):断言a是是b的一个实例,不是则测试用例通过。


3.TestSuite类的属性如下:(组织用例时需要用到)

['__call__', '__class__', '__delattr__', '__dict__', '__doc__', '__eq__', '__format__', '__getattribute__', '__hash__', '__init__', '__iter__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_addClassOrModuleLevelException', '_get_previous_module', '_handleClassSetUp', '_handleModuleFixture', '_handleModuleTearDown', '_tearDownPreviousClass', '_tests', 'addTest', 'addTests', 'countTestCases', 'debug', 'run']

说明:

addTest(): addTest()方法是将测试用例添加到测试套件中,如下方,是将test_baidu模块下的BaiduTest类下的test_baidu测试用例添加到测试套件。

suite = unittest.TestSuite()

suite.addTest(test_baidu.BaiduTest('test_baidu'))


4.TextTextRunner的属性如下:(组织用例时需要用到)

['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_makeResult', 'buffer', 'descriptions', 'failfast', 'resultclass', 'run', 'stream', 'verbosity']

说明:

run(): run()方法是运行测试套件的测试用例,入参为suite测试套件。

runner = unittest.TextTestRunner()

runner.run(suite)


二、使用unittest框架编写测试用例思路

设计基本思路如下:

Project:使用unittest框架编写测试用例思路'''#3.导入unittest模块import unittest#4.定义测试类,父类为unittest.TestCase。#可继承unittest.TestCase的方法,如setUp和tearDown方法,不过此方法可以在子类重写,覆盖父类方法。#可继承unittest.TestCase的各种断言方法。class Test(unittest.TestCase):

    #5.定义setUp()方法用于测试用例执行前的初始化工作。#注意,所有类中方法的入参为self,定义方法的变量也要“self.变量”#注意,输入的值为字符型的需要转为int型def setUp(self):

        self.number=raw_input('Enter a number:')

        self.number=int(self.number)#6.定义测试用例,以“test_”开头命名的方法#注意,方法的入参为self#可使用unittest.TestCase类下面的各种断言方法用于对测试结果的判断#可定义多个测试用例#最重要的就是该部分def test_case1(self):

        print self.number

        self.assertEqual(self.number,10,msg='Your input is not 10')


    def test_case2(self):

        print self.number

        self.assertEqual(self.number,20,msg='Your input is not 20')

    @unittest.skip('暂时跳过用例3的测试')

    def test_case3(self):

        print self.number

        self.assertEqual(self.number,30,msg='Your input is not 30')#7.定义tearDown()方法用于测试用例执行之后的善后工作。#注意,方法的入参为selfdef tearDown(self):

        print'Test over'#8如果直接运行该文件(__name__值为__main__),则执行以下语句,常用于测试脚本是否能够正常运行if__name__=='__main__':#8.1执行测试用例方案一如下:#unittest.main()方法会搜索该模块下所有以test开头的测试用例方法,并自动执行它们。#执行顺序是命名顺序:先执行test_case1,再执行test_case2    unittest.main()'''#8.2执行测试用例方案二如下:#8.2.1先构造测试集#8.2.1.1实例化测试套件    suite=unittest.TestSuite()#8.2.1.2将测试用例加载到测试套件中。#执行顺序是安装加载顺序:先执行test_case2,再执行test_case1    suite.addTest(Test('test_case2'))    suite.addTest(Test('test_case1'))#8.2.2执行测试用例#8.2.2.1实例化TextTestRunner类    runner=unittest.TextTestRunner()#8.2.2.2使用run()方法运行测试套件(即运行测试套件中的所有用例)    runner.run(suite)

''''''#8.3执行测试用例方案三如下:

#8.3.1构造测试集(简化了方案二中先要创建测试套件然后再依次加载测试用例)

#执行顺序同方案一:执行顺序是命名顺序:先执行test_case1,再执行test_case2

    test_dir = './'

    discover = unittest.defaultTestLoader.discover(test_dir, pattern='test_*.py')

#8.3.2执行测试用例

#8.3.2.1实例化TextTestRunner类

    runner=unittest.TextTestRunner()

#8.3.2.2使用run()方法运行测试套件(即运行测试套件中的所有用例)

    runner.run(discover)  '''

使用方案一执行测试用例结果如下:

Enter a number:10

10

Test over

Enter a number:.10

Fs

Ran 3 tests in 6.092s

FAILED (failures=1, skipped=1)

10

Test over

因为先执行test_case1,再执行test_case2,所以第一次输入10时,执行通过,返回. 第二次输入10时,执行不通过,返回F,最终一个用例通过,一个用例失败,还有一个用例是直接跳过的(装饰器)。

使用方案二执行测试用例结果如下:

Enter a number:10

10

Test over

Enter a number:F10

.

Ran 2 tests in 4.973s

FAILED (failures=1)

10

Test over

因为先执行test_case2,再执行test_case1,所以第一次输入10时,执行不通过,返回F , 第二次输入10时,执行通过,返回. ,最终一个用例通过,一个用例失败。


三、使用unittest框架,框架目录介绍。

框架目录结构:

四,封装。

代码如下:

import os

import time

import xlrd

from selenium.webdriver.common.action_chainsimport ActionChains

from selenium.webdriver.supportimport expected_conditionsas EC

from selenium.webdriver.support.waitimport WebDriverWait

from selenium.common.exceptionsimport WebDriverException

from utils.configimport REPORT_PATH

from utils.logimport logger

from selenium.webdriver.support.uiimport Select

# from UI_AUTOMATION.test.testcase.gb_pc_form_case import FormTestCase

from timeimport sleep

class BasePage:

def __init__(self, driver):

self.driver = driver

def get(self, url, maximize_window=True, time_sync=30):

self.driver.get(url)

if maximize_window:

self.driver.maximize_window()

self.driver.implicitly_wait(time_sync)

return self

    def is_element_exist(self, *xpath):#快速定位元素是否存在,不等待。

        flag =True

        browser =self.driver

try:

browser.find_element_by_xpath(xpath)

return flag

except:

flag =False

            return flag

def find_element_now(self, *loc):

try:

self.driver.find_element_by_xpath(loc)

return True

        except AttributeError:

print(u"%s 页面中未能找到 %s 元素" % (self, loc))

return False

    def find_element(self, *loc):

try:

WebDriverWait(self.driver, 4).until(EC.visibility_of_element_located(loc))# 等待元素在页面可见

            return self.driver.find_element(*loc)

except AttributeError:

print(u"%s 页面中未能找到 %s 元素" % (self, loc))

def find_elements(self, *loc):

try:

items = WebDriverWait(self.driver, 10).until(EC.presence_of_all_elements_located(loc))# 等待元素在DOM都出现

            return items

except AttributeError:

print(u"%s 页面中未能找到 %s 元素" % (self, loc))

def elements_text(self, *loc):

items = []

items_elements =self.find_elements(*loc)

for itemin items_elements:

items.append(item.text.strip())

return items

def move_to_element(self, *loc):

aim_loc =self.find_element(*loc)

ActionChains(self.driver).move_to_element(aim_loc).perform()

def click(self, *loc):

try:

self.find_element(*loc).click()

except Exception as msg:

self.save_screen_shot()

# self.driver.get_screenshot_as_base64()

            logger.error("Element {} is not clickable".format(loc))

def clickn(self, n=2, *loc):

try:

self.find_element(*loc)[n].click()

except Exception as msg:

self.save_screen_shot()

logger.error("Element {} is not clickable".format(loc))

def send_keys(self, value, *loc):

sleep(0.3)

element =self.find_element(*loc)

element.click()

element.clear()

element.send_keys(value)

def send_Skeys(self,  value, *loc):

sleep(0.3)

element = Select(self.find_element(*loc))

element.select_by_value(value)

def add_img(self):

self.imgs.append(self.driver.get_screenshot_as_base64())

return True

    # def save_screen_shot(self):

    def save_screen_shot(self, name='screen_shot'):

day = time.strftime('%Y%m%d', time.localtime(time.time()))

screenshot_path = REPORT_PATH +'\screenshot_%s' % day

if not os.path.exists(screenshot_path):

os.makedirs(screenshot_path)

tm = time.strftime('%H%M%S', time.localtime(time.time()))

screenshot =self.driver.save_screenshot(screenshot_path +'\\%s_%s.png' % (name, tm))

return screenshot

# self.imgs.append(self.driver.get_screenshot_as_base64())

# return True

    def find_title(self, *loc):

try:

WebDriverWait(self.driver, 4).until(EC.visibility_of_element_located(loc))# 等待元素在页面可见

            return self.driver.find_element(*loc)

except AttributeError:

print(u"%s 页面中未能找到 %s 元素" % (self, loc))

def in_pages(self, txt):

return txtin self.driver.page_source

def switch_frame(self, loc):

self.driver.switch_to.frame(loc)

def default_content(self):

self.driver.switch_to.default_content()

def switch_window(self, n=1):

# 打开顺序:1,2,3,4,5

        # 句柄顺序:0,4,3,2,1

        newest_window =self.driver.window_handles[n]

self.driver.switch_to.window(newest_window)

@staticmethod

    def get_latest_file(download_dir):

"""获取最新的文件"""

        lists = os.listdir(download_dir)

lists.sort(key=lambda fn: os.path.getmtime(download_dir +'\\' + fn))

file_path = os.path.join(download_dir, lists[-1])

return file_path

@staticmethod

    def get_data(file_path):

book = xlrd.open_workbook(file_path)

sheet = book.sheet_by_index(0)

rows = []

cols = []

for jin range(0, sheet.nrows):

rows.append(list(sheet.row_values(j, 0, sheet.ncols)))

for iin range(0, sheet.ncols):

cols.append(list(sheet.col_values(i, 0, sheet.nrows)))

return rows, cols, book.sheet_names()

# 返回3个列表组成的元组

五,业务分离,元素分离,数据分离。

首先数据为什么要分离,安全,代码不冗余,便于维护,较少后期维护成本。

业务分离:

部分代码入下:

from UI_AUTOMATION.utils.configimport Config

from selenium.webdriver.support.uiimport Select

import pymysql

from UI_AUTOMATION.test.page.pageconfig.haoseleniumimport *

from UI_AUTOMATION.utils.configimport Config

from selenium.webdriver.support.waitimport WebDriverWait

from UI_AUTOMATION.test.page.pageconfig.connectimport GBConnect

from UI_AUTOMATION.test.page.base_pageimport *

from UI_AUTOMATION.test.page.PC.pc_locatorsimport *

from UI_AUTOMATION.test.page.PC.pc_home_pageimport *

class GBBaseCase(BasePage):

def __init__(self, driver):

self.Connection ='keep-alive'

        self.driver = driver

c = Config().get('GB')

self.ua = c.get('UA')

self.url = c.get('GBURL')

self.username = c.get('GBusername')

self.password = c.get('GBpassword')

self.GBloginURL = c.get('GBloginURL')

self.GBgood = c.get('GBgood')

self.PPusername = c.get('PPusername')

self.PPpassword = c.get('PPpassword')

self.GBselfcenter = c.get('GBselfcenter')

self.userId = c.get('userId')

c = Config().get('mysql')

self.host = c.get('host')

self.post = c.get('post')

self.user = c.get('user')

self.passwd = c.get('passwd')

self.db = c.get('db')

# print(self.userId)

    def add_img(self):

self.imgs.append(self.get_screenshot_as_base64())

return True

    def gb_login(self):

# self.headers = {'User-Agent': self.ua}

# self.driver = driver

        pc = HomePage(self.driver)

lg = LoginPage(self.driver)

pc.get(self.GBloginURL)

# self.add_img()

        # pc.close_pop_win()  #关闭弹窗

        # pc.sign_in()      #点击进入登录页面

        lg.login(self.username, self.password)

# WebDriverWait(self.driver, 10).until(EC.title_is("GearBest: Online Shopping - Best Gear at Best Prices"))

        sleep(1)

def gb_goodtobuy(self):

# self.driver.refresh()

        sleep(0.5)

# self.driver.set_page_load_timeout(5)

        try:

self.driver.get(self.GBgood)

b =0

            while b !=5:

try:

self.find_element(*GoodsInfoPageLoc.buy_button)

b =5

                except:

b = b +1

                    self.driver.refresh()

except TimeoutException:

self.driver.execute_script('window.stop()')

# self.driver.execute_script("var q=document.body.scrollTop=300")

        self.find_element(*GoodsInfoPageLoc.buy_button)

try:

self.click(*GoodsInfoPageLoc.num_plus)

self.click(*GoodsInfoPageLoc.buy_button)

except:

self.driver.refresh()

self.click(*GoodsInfoPageLoc.num_plus)

self.click(*GoodsInfoPageLoc.buy_button)

sleep(5)

def gb_goodtopaypal(self):

self.driver.set_page_load_timeout(5)

self.driver.refresh()

sleep(2)

try:

self.get(self.GBgood)

b =0

            while b !=5:

try:

self.find_element_now(*GoodsInfoPageLoc.paypal_button)

self.click(*GoodsInfoPageLoc.paypal_button)

b =5

                except:

b = b +1

                    self.driver.refresh()

except TimeoutException:

self.driver.execute_script('window.stop()')

self.find_element(*GoodsInfoPageLoc.paypal_button)

try:

self.click(*GoodsInfoPageLoc.num_plus)

self.click(*GoodsInfoPageLoc.paypal_button)

except:

self.driver.refresh()

self.click(*GoodsInfoPageLoc.num_plus)

self.click(*GoodsInfoPageLoc.paypal_button)

sleep(5)

def gb_placeorder(self):

# self.headers = {'User-Agent': self.ua}

# self.driver.execute_script("var q=document.documentElement.scrollTop=500")

        sleep(1)

try:

self.driver.switch_to.alert

self.driver.switch_to.alert.accept()# 点击弹出上面的X按钮

        except:

pass

        try:

self.click(*PlaceInfoPageLoc.place_button)# pleace your order

        except:

self.driver.refresh()

sleep(1)

self.driver.execute_script("var q=document.documentElement.scrollTop=500")

try:

self.click(*PlaceInfoPageLoc.place_button)# pleace your order

            except:

self.driver.refresh()

sleep(1)

self.click(*PlaceInfoPageLoc.place_button)# pleace your order

        sleep(4)

def get_payurl(self):

# self.headers = {'User-Agent': self.ua}

        url = GBConnect().GB_payurl()

self.get(url)

self.driver.maximize_window()

self.find_element(*PaymentInfoPageLoc.pay_button)

self.driver.refresh()

print('收银台url:', self.driver.current_url)

sleep(0.5)

def get_payurl_m(self):

# self.headers = {'User-Agent': self.ua}

        url = GBConnect().GB_payurl()

self.get(url)

# self.driver.maximize_window()

# self.find_element(*PaymentInfoPageLoc.pay_button)

# self.driver.refresh()

        print('收银台url:', self.driver.current_url)

sleep(0.5)

def paymentplatform(self):

# self.headers = {'User-Agent': self.ua}

        self.find_element(*PaymentInfoPageLoc.pay_button)

print('收银台url:', self.driver.current_url)

try:

self.click(*PaymentInfoPageLoc.paypal_src)

self.driver.find_element_by_xpath("//*[@class='placeOrder btn block toPayBtn']").click()# 点击购买placeOrder btn block toPayBtn

        except Exception as msg:

print(u"异常原因%s" % msg)

pamentordersn =self.driver.find_element_by_xpath("//*[@class='pc_orderinf']/dl[1]/dd").text

print("收银台订单号:", pamentordersn)

# BaseTestCase.add_img()

            self.add_img()

raise

        sleep(2)

def obs_credit_channel(self, channel1):

js ='window.open("http://www.obs-pay.com");'  # 通过执行js,开启一个新的窗口

        self.driver.execute_script(js)

pay_windows =self.driver.current_window_handle

window_1 =self.driver.current_window_handle

# 获得打开的所有的窗口句柄

        windows =self.driver.window_handles

# 切换到最新的窗口

        for current_windowin windows:

if current_window != window_1:

self.driver.switch_to.window(current_window)

# self.get("http://www.obs-pay.com")

        sleep(1)

# obs_handle = self.driver.current_window_handle

# self.obs_handle = obs_handle

# sleep(0.5)

        self.driver.find_element_by_xpath("//*[@name='username']").send_keys("zhangwei")

self.driver.find_element_by_xpath("//*[@name='password']").send_keys("zhang1wei")

sleep(0.5)

self.driver.find_element_by_xpath("//input[@type='submit']").click()

sleep(1)

self.driver.get("http://www.obs-pay.com/#/pay/channel-platform-country/list")

sleep(1.5)

self.driver.find_element_by_xpath("//*[contains(text(),'Turkey')]/../../td[5]/div/button[1]/span").click()

sleep(0.5)

start_ele ='//*[contains(text(), "%s")]' % channel1

end_ele ='//*[contains(text(), "%s")]/../li[1]' % channel1

start =self.driver.find_element_by_xpath(start_ele)

end =self.driver.find_element_by_xpath(end_ele)

actions = ActionChains(self.driver)

actions.drag_and_drop(start, end)

actions.perform()

sleep(0.5)

self.driver.find_element_by_xpath("//*[contains(text(),'确定')]").click()

sleep(0.5)

self.driver.close()

self.driver.switch_to.window(pay_windows)

def payment_creditcard(self):

self.find_element(*PaymentInfoPageLoc.pay_button)

self.driver.refresh()

sleep(0.5)

print('收银台url:', self.driver.current_url)

self.obs_credit_channel("checkout_credit")

# pay_windows = self.driver.current_window_handle

# GBBaseCase.obs_creditcard()

# sleep(0.5)

# self.driver.switch_to.window(pay_windows)

        self.click(*PaymentInfoPageLoc.creditcard_src)

self.send_keys("hao", *PaymentInfoPageLoc.creditcard_holder)

self.send_keys("6111111111117", *PaymentInfoPageLoc.creditcard_Number)

self.send_keys("10", *PaymentInfoPageLoc.creditcard_Code)

self.send_Skeys("4", *PaymentInfoPageLoc.creditcard_mouth)

self.send_Skeys("2035", *PaymentInfoPageLoc.creditcard_day)

sleep(0.8)

self.click(*PaymentInfoPageLoc.pay_button)

sleep(4)

def gb_checkorder(self):

        paymentresult =self.driver.find_element_by_xpath("//*[@class='pay_title']").text

print("支付结果提示语:", paymentresult)

global ordersn

try:

ordersn =self.driver.find_element_by_xpath("//*[@class='payOnline_sucess']/p[2]/b[1]").text# paid

        except:

try:

ordersn =self.driver.find_element_by_xpath(

"//*[@class='payOnline_padding']/p[1]/b[1]").text# pending

            except:

try:

ordersn =self.driver.find_element_by_xpath(

"//*[@class='payOffline_default']/p[1]/b[1]").text# Appreciate

                except:

try:

ordersn =self.driver.find_element_by_xpath(

"//*[@class='pay_title']/em[1]").text# Submitting

                    except:

print("fail or no_result")

ordersn =str(ordersn)

if len(ordersn) ==20:

pass

        else:

ordersn = ordersn[:-1]

print("订单号为:", ordersn)

connect = pymysql.connect(host=self.host, port=self.post, user=self.user, passwd=self.passwd, db=self.db,

                                  charset='utf8')

cursor = connect.cursor()

cursor.execute("SELECT pay_status FROM pay_gateway_16 WHERE parent_order_sn=('%s')" % (ordersn))

status = cursor.fetchall()

status =str(status)

status = status[2:3]

print("此订单状态为:【%s】" % (status), " (0-未支付 1-处理中 2-已支付 3-退款中 4-退款成功 5退款失败 6支付失败)")

cursor.close()

# self.driver.refresh()

    except Exception as msg:

print(u"异常原因%s" % msg)

# self.add_img()

        self.save_screen_shot()

raise


元素分离:

部分代码入下:

from selenium.webdriver.common.byimport By

class PublicLoc:

"""公共组件"""

class LoginPageLoc:

"""登录"""

    email = (By.ID, "email")

password = (By.ID, "password")

sign_in = (By.ID, "js-btnSubmit")

class HomePageLoc:

"""首页"""

    # 标题栏

    user_info = (By.CSS_SELECTOR, "a.siteHeader_userAccountLink")

sign_in = (By.CSS_SELECTOR, "a.siteHeader_userLinkLogin")

my_fav = (By.XPATH, "//header/div[2]/div[3]/div[1]/div[1]/div[1]/p/a")

cart = (By.XPATH, "//header/div[2]/div[3]/div[3]/a[2]/p")

# 用户信息菜单

    my_order = (By.XPATH, "//ul/li[2]/a")

my_tickets = (By.XPATH, "//ul/li[3]/a")

my_message = (By.XPATH, "//ul/li[4]/a")

my_wallet = (By.XPATH, "//ul/li[5]/a")

my_points = (By.XPATH, "//ul/li[6]/a")

my_profile = (By.XPATH, "//ul/li[7]/a")

my_coupon = (By.XPATH, "//ul/li[8]/a")

logout = (By.CLASS_NAME, "js-logout")

# 弹窗

    new_user_pop = (By.CLASS_NAME, "newUserPop")

close_pop = (By.CLASS_NAME, "layui-layer-setwin")

class UserInfoPageLoc:

"""用户信息页"""

    goods_images = (By.CSS_SELECTOR, "a.orderItem_thumb")

goods_names = (By.CSS_SELECTOR, "a.orderItem_title")

class GoodsInfoPageLoc:

"""商品详情页"""

    qty = (By.CLASS_NAME, "compInputNumber_input")

num_plus = (By.CLASS_NAME, "compInputNumber_reduce")

num_reduce = (By.CLASS_NAME, "compInputNumber_plus")

buy_button = (By.XPATH, "//*[@class='goodsIntro_btnWrap js-buyBtnWrap']/a[2]")

paypal_button = (By.XPATH, "//*[@class='goodsIntro_btnWrap js-buyBtnWrap']/a[2]")

class PlaceInfoPageLoc:

"""订单确认页"""

    # place_button = (By.XPATH, "//a[@class='ckOl_totalBtn btn middle strong']")

    place_button = (By.XPATH, "//a[contains(text(),'Place Your Order')]")

class PaymentInfoPageLoc:

"""收银台"""

    pay_button = (By.XPATH, "//*[@class='placeOrder btn block toPayBtn']")

pay_currencyselect = (By.XPATH, "//*[@class='currency_select']")

pay_currencyconfirm = (By.XPATH, "//*[@class='currency_select']/option[2]")

Wallet_ele = (By.XPATH, "//span[contains(text(),'My Wallet')]")

Wallet_input = (By.XPATH, "//*[@placeholder='Please enter the Wallet password']")

paypal_src = (By.XPATH, '//*[@src="https://uidesign.zafcdn.com/ZF/image/z_promo/20190418_9285/PayPal@2x.png"]')

creditcard_src = (By.XPATH, '//*[@src="https://uidesign.gbtcdn.com/GB/images/others/check_out/57x35/visa.png?imbypass=true"]')

creditcard_holder = (By.XPATH, "//*[@placeholder='Card Holder']")

creditcard_Number = (By.XPATH, "//*[@placeholder='Card Number']")

creditcard_Code = (By.XPATH, "//*[@placeholder='Security Code']")

creditcard_mouth = (By.XPATH, '//*[@curchannel="CREDITCARD"]/div[2]/div/select')

creditcard_day = (By.XPATH, '//*[@curchannel="CREDITCARD"]/div[3]/div/select')

ebanxinstalment_src = (By.XPATH, '//*[@src="https://uidesign.gbtcdn.com/GB/images/others/check_out/57x35/elo.png?imbypass=true"]/../../em[1]/img')

ebanxinstalment_installments = (By.XPATH, '//*[@class="formList_select installments"]/option[2]')

ebanxinstalment_CPF = (By.XPATH, "//*[@placeholder='CPF']")

ebanxinstalment_Titular = (By.XPATH, "//*[@placeholder='Titular do cartão']")

ebanxinstalment_Nmero = (By.XPATH, "//*[@placeholder='Número de cartão']")

ebanxinstalment_Cdigo = (By.XPATH, "//*[@placeholder='Código de segurança']")

ebanxinstalment_Month = (By.XPATH, '//*[@name="expirationMonth"]')

ebanxinstalment_Year = (By.XPATH, '//*[@name="expirationYear"]')

MXCC_Cdigo = (By.XPATH, "//*[@placeholder='Código de seguridad']")

BEBC_holder = (By.XPATH, '//*[@curchannel="ADN_BEBC"]/div[4]/div/input')

EPS_src = (By.XPATH, '//*[@src="https://icss1.gearbest.com/imagecache/GB2/images/domeimg/pay_method/eps.jpg"]')

SOFORT_src = (By.XPATH, '//*[@src="https://uidesign.gbtcdn.com/GB/images/others/check_out/sofort.png?02"]')

DEGP_src = (By.XPATH, '//*[@src="https://icss1.gearbest.com/imagecache/GB2/images/domeimg/pay_method/giropay.jpg"]')

LipaPay_src = (By.XPATH, '//*[@src="https://uidesign.gbtcdn.com/check_out/Lipapay.png?impolicy=ture"]')

MYOB_src = (By.XPATH, '//*[@src="https://uidesign.gbtcdn.com/check_out/ADN_MYOB.png?impolicy=high"]')

THOB_src = (By.XPATH, '//*[@src="https://css.zafcdn.com/imagecache/ZF_V2/images/domeimg/pay_method/ADN_THOB.jpg"]')

BANK_TRANSFER_src = (By.XPATH, '//*[@src="https://icss1.gearbest.com/imagecache/GB2/images/domeimg/pay_method/WiredTransfer.jpg"]')

WESTERN_src = (By.XPATH, '//*[@src="https://icss1.gearbest.com/imagecache/GB2/images/domeimg/pay_method/WesternUnion.jpg"]')

EBX_SVPG_src = (By.XPATH, '//*[@src="https://uidesign.gbtcdn.com/check_out/Servipag.png?impolicy=high"]')

EBX_SVPG_doc = (By.XPATH, "//*[@curchannel='EBX_SVPG']/div[1]/div/select")

EBX_SVPG_number = (By.XPATH, "//*[@curchannel='EBX_SVPG']/div[2]/div/input")

ADN_TRSP_src = (By.XPATH, '//*[@src="https://uidesign.gbtcdn.com/check_out/Trustpay.png?impolicy==true"]')

ADN_TRSP_issuerId = (By.XPATH, "//*[@name='issuerId']")

Postepay_src = (By.XPATH, '//*[@src="https://uidesign.gbtcdn.com/GB/images/others/check_out/postepay.jpg"]')

PagoEfectivo_src = (By.XPATH, '//*[@src="https://icss1.gearbest.com/imagecache/GB2/images/domeimg/pay_method/pagoefectivo.png"]')

SQ_ESCC1_src = (By.XPATH, '//*[@src="https://uidesign.gbtcdn.com/check_out/SQ_ESCC1.png"]')

poli_src = (By.XPATH, '//*[@src="https://uidesign.gbtcdn.com/check_out/poli_m.png?impolicy=high"]')

Webmoney_src = (By.XPATH, '//*[@src="https://icss1.gearbest.com/imagecache/GB2/images/domeimg/pay_method/webmoney.jpg"]')

WPG_Pay_src = (By.XPATH, '//*[@src="https://uidesign.gbtcdn.com/check_out/Gpay.png?03"]')

class ThirdInfoPageLoc:

"""支付第三方"""

    mainSubmit = (By.XPATH, "//*[@id='mainSubmit']")

GC_password = (By.XPATH, "//*[@type='password']")

GC_Entry = (By.XPATH, "//*[@name='UsernamePasswordEntry']")

poli_continue = (By.XPATH, "//*[@name='continue']")

poli_Username= (By.XPATH, "//*[@name='Username']")

poli_Password = (By.XPATH, "//*[@name='Password']")

poli_LoginButton = (By.XPATH, "//*[@name='LoginButton']/../button")

poli_textContinue = (By.XPATH, "//*[contains(text(),'Continue')]")

poli_primarybutton = (By.XPATH, "//*[@class='button stp-button primary-button']")

poli_ConfirmButton = (By.XPATH, "//*[@name='ConfirmButton']/../button")

WPG_Pay_email = (By.XPATH, "//*[@type='email']")


数据分离:敏感数据

六,一个测试用例代码的实现,整个流程。

1.写testcase,基础case测试用例脚本。

比如登录:

def gb_login(self):

# self.headers = {'User-Agent': self.ua}

pc = HomePage(self.driver) 

lg = LoginPage(self.driver)

pc.get(self.GBloginURL)

lg.login(self.username, self.password)

其中取入下数据:

上图取这里的数据:

class LoginPageLoc:

"""登录"""

    email = (By.ID, "email")

password = (By.ID, "password")

sign_in = (By.ID, "js-btnSubmit")

综上:完成了一个登录。

第二步:

登录脚本case加入suilt套件:


import unittest

from seleniumimport webdriver

from UI_AUTOMATION.test.page.PC.gb_pc_base_caseimport GBBaseCase

from UI_AUTOMATION.test.page.pageconfig.connectimport GBConnect

# from UI_AUTOMATION.test.page.form

# from ..page.form.form_pc import *

# unittest.TestCase

class BaseTestCase(unittest.TestCase):

@classmethod

    def setUpClass(cls):

# option = webdriver.ChromeOptions()

# option.add_argument('headless')  # 静默模式

# cls.driver = webdriver.Chrome(chrome_options=option)

        cls.driver = webdriver.Chrome()

@classmethod

    def tearDownClass(cls):

# cls.driver.quit()

        pass

    # def add_img(self):

#    self.imgs.append(self.driver.get_screenshot_as_base64())

#    return True

    def setUp(self):

# 在是python3.x 中,如果在这里初始化driver ,因为3.x版本 unittest 运行机制不同,会导致用力失败时截图失败

        self.imgs = []

self.addCleanup(self.cleanup)

def cleanup(self):

pass

    def login_GB(self):

GBBaseCase(self.driver).gb_login()

def test_GB_wallet(self):

'''电子钱包支付'''

GBConnect().GB_adress_Turkey()

GBBaseCase(self.driver).gb_goodtobuy()

GBBaseCase(self.driver).gb_placeorder()

GBBaseCase(self.driver).payment_wallet()

GBBaseCase(self.driver).gb_checkorder()

def test_GB_paypal(self):

if __name__ =="__main__":

unittest.main()

第三步,run启动程序脚本

import time

import unittest

from UI_AUTOMATION.test.testcase.gb_pc_caseimport BaseTestCase

from UI_AUTOMATION.utils.configimport REPORT_PATH

from UI_AUTOMATION.utils.haoemailimport Email

from UI_AUTOMATION.test.page.pageconfig.CIimport GBConnect

# # 构造测试集

suite = unittest.TestSuite()

suite.addTest(BaseTestCase('login_GB'))

'''

def create_test_suite():

test_list_path = "../testcase"

test_unit = unittest.TestSuite()

discover = unittest.defaultTestLoader.discover(test_list_path, pattern="test_*cii.py")

for test_suite in discover:

for test_case in test_suite:

test_unit.addTest(test_case)

print(test_case)

return test_unit

all_test = create_test_suite()

'''

now_time = time.strftime('%Y%m%d-%H%M%S', time.localtime())

report = REPORT_PATH +'\\' +'PAY_Report '+ now_time +'.html'

# print(report)

### 从代码执行结果里面获取数据      HTMLTestRunner

with open(report,"wb")as outfile:

runner = HTMLTestRunner(stream=outfile,title=u"GB-PC-PAY_UITest",description=u"用例执行情况:",verbosity=2,retry=0,save_last_try=False)

aa = runner.run(suite)

e = Email(path=report,message='''

本邮件是支付UI自动化测试报告,请下载或者使用浏览器查看附件内容.

如果有任何问题,请及时联系:测试组. Thank you!

--------------------------------------------

深圳市环球易购电子商务有限公司

技术中心\电子项目部\质量管控组

姜家豪

TEL:18682436420

Email:jiangjiahao@globalegrow.com

''')

e.send()

'''***CI确认发送:‘y’***"

***CI不发送:‘n’***'''

while 1:

choose =input('输入命令:')

if choose =='y' and 'Y':

print("CI已发送!")

break

    if choose =='n' and 'N':

print("CI已取消发送,并程序结束!!!")

exit(0)

else:

print("输入命令有误,请重新输入!")

e = Email(path=report,message='''

本邮件是支付UI自动化测试报告,请下载或者使用浏览器查看附件内容.

如果有任何问题,请及时联系:测试组. Thank you!

--------------------------------------------

深圳市环球易购电子商务有限公司

技术中心\电子项目部\质量管控组

姜家豪

TEL:18682436420

Email:jiangjiahao@globalegrow.com

''')

e.send()

conn = GBConnect()##发CI接口

conn.CI_pc_date(runner, aa)

### 通过打开报告,从页面获取数据

# with open(report, "wb") as outfile:

#    runner = HTMLTestRunner(stream=outfile, title=u"GB-PC-PAY_UITest", description=u"用例执行情况:", verbosity=2, retry=0, save_last_try=False)

#    runner.run(suite)

#    conn = GBConnect()

#    conn.CI_pc_page(report, runner)


测试报告:

七,个人理解与寄语。

首先,UI自动化不仅能提高自己的编码水平,重要的是在工作过程中能有另一类思想去实现自己的目的。

其次,工作效率大大提升,尤其在回归的时候,节省人力成本很多。

最后,此框架适用于各端,有志同道合着和与我深入探讨。

代码涉及公司很多敏感信息,原谅不能公开。

希望大家有一个提升和突破。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,482评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,377评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,762评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,273评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,289评论 5 373
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,046评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,351评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,988评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,476评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,948评论 2 324
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,064评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,712评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,261评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,264评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,486评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,511评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,802评论 2 345

推荐阅读更多精彩内容