python实现Web UI自动化测试需要具备的技能

python实现Web UI自动化测试需要具备的技能

自动化测试简介

练习神器:http://sahitest.com/demo

概念

自动化测试:人为驱动的测试行为转化为机器执行的一种过程。

自动化测试分类:
单元自动化测试(代码)
接口自动化测试(接口)
UI自动化测试(UI页面)
场景适用:
功能比较稳定的项目的:冒烟测试、缺陷回归测试、业务场景覆盖测试
UI自动化测试
UI自动化测试脚本思路
  1. 定位页面元素
  2. 对元素执行操作
  3. 自动检查结果
Selenium简介

特点

  1. 免费开源
  2. 支持多浏览器-IE、FireFox、Chrome、Safari

** 组成部分**

  1. Selenium WebDriver
    属于核心部分,提供各种各样的接口,供用户实现Web UI自动化测试的功能
  2. Selenium IDE
    可以录制和回放浏览器操作,从而快速创建自动化测试
  3. Selenium Grid
    自动化脚本分发到不同的测试机器上进行执行
WebDriver组件

WebDriver

WebDriver通过Brower Driver与浏览器进行通过,并且以同样的路径来接收浏览器返回的信息

缺点

webDriver擅长配合Brower-Driver与浏览器进行通讯,但是不擅长如何比事物,如何断言,所以我们要使用各种框架来解决,本书选择Python语言作为开发语言,使用Unittest和Pytest作为框架,测试框架负责执行WebDriver中与测试相关的步骤

测试环境搭建

Python

下载地址:https://www.python.org/downloads/windows/

Doc:存放python帮助文档的文件夹
Lib:将来安装第三方库都会存放在该文件夹下
libs:内置库(可以直接引用的模块)
Scripts:包含可执行的文件

Selenium

  1. 安装selenium:pip install selenium
  2. 安装WebDriver:下载并且放到任一目录进行环境变量配置或者放到python路径下即可

Pycharm

提高程序开发时的效率

下载地址:https://www.jetbrains.com/pycharm/download/#section=windows

第三方包

​ 具体详情操作Pycharm为准

Python知识
Python基本数据类型

数值
字符串
列表
字典
集合

顺序、分支、循环语句
Python函数、模块
Python类、实例
文件I/O操作
json和yaml文件
面向对象编程

OOP:object Oriented programming;属于一种设计思想,把计算机程序视为一组对象的集合,每个对象都可以接收其他对象发过来的消息,并处理这些消息,计算机程序执行过程就是一系列消息在各个对象之间传递的过程。

前端知识储备
HTML基础知识

参考菜鸟教程中HTML知识即可

CSS相关知识

CSS是层叠样式表,定义如何展示HTML元素

JavaScript相关知识

在实施自动化测试过程中我们需要借助JavaScript来操作页面元素,常用于web应用开发,为页面添加各式各样的动态功能

Selenium基础方法
selenium常用方法
#浏览器驱动
driver = webdriver.Chrome()
#获取url
driver.get('http://baidu.com')
#设置为最大化
driver.maximize_window()
#获取title属性
driver.title

对于多窗口操作需要获取窗口的唯一标识:句柄

#获取当前句柄
driver.current_window_handle
#获取所有句柄
all = driver.window_handles
#切换句柄,切换时可以进行判断句柄的准确性等
driver.switch_to.window(all[0])
Selenium元素定位方法

常用元素定位方法

#使用id进行定位
#使用xpath定位元素
#使用css方式进行定位

鼠标操作

#单击操作
ele=driver.element_by_link_text('新闻')
ele.click()
#内置鼠标操作
from selenium.webdriver.common.action_chains import ActionChains
	#右击操作
	ActionChains(driver).context_click(ele).perform()
	#鼠标指针悬浮操作
	ActionChains(driver).move_to_element(ele).perform()
	#鼠标拖拽操作
	ActionChains(driver).drag_and_drop(source,target).perform()
Unitest框架
unittest四个重要的概念

测试固件
测试之前或者之后做一些操作,常用的test fixture有:setup、teardown、setupclass、teardownclass
测试用例
测试用例是unittest执行测试的最小单元,它通过unittest提供的assert方法验证特定的操作或者以后得到的具体响应
测试用例定义非常简单,如何合理地组织用例:

  1. 多个测试用例文件尽量不要存在依赖关系,因为一旦被依赖的测试用例执行失败,后续有依赖关系的测试用例也会失败
  2. 一个测试用例可以添加多个断言进行检查

测试套件
一组测试用例,作用是将多个测试用例放在一起,执行一个测试套件就可以将这些测试用例全部执行
测试运行器
测试运行器用来执行测试用例,并且返回测试用例的执行结果,可以使用图形、表格、文本等方式将测试结果形象地展现出来,HTMLTestRunner

import unnitest
class TestStorm(unittest.TestCase):
	def setUp(self):
		print('setup')
	def test_first(self):
		self.assertEqual('storm','storm')
	def tearDown(self):
		print ('teardown')
if __name__ =='__main__':
	unittest.main()

测试固件的说明顺序

import unittest
class TestStorm(unittest.TestCase):
	@classmethod #class方法装饰器
	def setUpClass(cls):
		print ('setUpClass')
	def setUp(self):#每个测试用例执行前执行
		print ('setup')
	def test_first(self):
		print ('first')
	def test_second(self):
		print ('second')
	def tearDown(self):#每个测试用例结束后执行
		print ('tearDown')
	@classmethod
	def tearDownClass(cls):
		print ('tearDownClass')
	if __name__ == '__main__':
		unittest.main()
	#执行结果
	setUpClass
	setup
	first
	tearDown
	setup
	second
	tearDown
	tearDownClass
unittest框架解决的问题

####### 测试用例的相关问题
unittest参数化也叫做数据驱动

对于测试用例来讲,如果是登录模块,我们要验证登录成功或登录失败,两个测试用例,两个的测试用例步骤其实是一样的,只不过传递的参数不一样,如果我们想降低代码的冗余性,可以讲脚本中的数据抽离出来,实现数据和代码的分离
unittest不支持参数化,我们需要借助第三方插件来实现
unittest+DDT

#DDT全称为Data-Driven Tests,意思是数据驱动测试,虽然unittest没有自带数据驱动功能,但DDT可以与之完美地结合
#install
C:\Users\Flysky>pip3 install ddt
from selenium import webdriver
import unittest
import ddt
@ddt.ddt
class TestLogin(unittest.TestCase):
	def setUp(self):
		self.driver=webdriver.Chrome()
		self.driver.maximize_window()
		self.driver.implicitly_wait(20)
		#访问“登录”页面
		self.driver.get("http://localhost:8080/redmine/login")
		'''
		1,使用ddt进行传递参数
		'''
	@ddt.data(['admin','123456','0'],['admin','000000','1'])
	@ddt.unpack
	def test_login(self,username,password,status):
	#获取用户名和密码输入并且输入内容点击登录
		login_name=self.driver.find_element_by_id("username")
		login_name.clear()
		login_name.send_keys(username)
		login_pwd=self.driver.find_element_by_id("password")
		login_pwd.clear()
		login_name.send_keys(password)
		login_btn=self.find_element_by_id('login-submit')
		login_btn.click()
	#对于登录失败或者成功后的页面提示验证
		if status =='0':
			ele=self.driver.find_element_by_id('flash_error')
			self.assertIn('无效的用户名',self.driver.page_source)
		if status =='1':
			name=self.driver.find_element_by_link_text(username)
			self.assertEqual(name.text,username)
		else:
			print ('参数化的状态只能为0或者1')
	def tearDown(self):
		self.driver.quit()
	
if __name__=='__main__':
	unittest.main()

PO设计模式

项目的易变性导致测试用例的维护成本越来越高,那我们使用PO设计模式来解决这个问题
开发可维护性高的测试脚本,对于自动化测试持续集成非常重要,如何去解决这些问题呢?
PO:page object是指页面元素的定位以及元素的操作分离,测试用例直接调用这些封装好的元素操作来组织用例,从而实现测试用例脚本和元素定位、操作的分离
虽然PO思想被广大测试同行认可,但是不同团队在项目实践过程中采用了不同的分层模式

PO+pytest+Selenium

整体的规划:将系统按页面分成三层结构

  1. 元素对象层
    封装定位元素的方法

  2. 元素操作层
    借助元素对象层封装的操作方法

  3. 业务场景层
    借助元素操作层封装当前页面的业务场景

|--------Package
|----------------pageobject
|-----------------------login_page.py
|----------------report
|----------------testcase

|----------------------test_001_login.py

对于login_page.py定义“查找元素类”

#页面元素对象层
class LoginPage(object):
	def __init__(self,driver):
		self.driver=dirver
	def find_username(self):
		ele=self.driver.find_element_by_id('username')
		return ele
	def find_password(self):
		ele = self.driver.find_element_by_id('password')
		return ele
	def login_btn(self):
		ele = self.driver.find_element_by_id('login-submit')
		return ele
	def find_login_name(self):
		ele = self.driver.find_element_by_id('loggedas')
		return ele
	def find_login_failed_info(self):
		ele= self.driver.find_element_by_id('flash_error')
		return ele
#页面元素操作层
class LoginOper(object):
	def __init__(self,driver)
		self.login_page =LoginPage(driver)
	def input_username(self,username):
		#对用户名文本框做clear和send_keys操作
		user = self.login_page.find_username()
		user.clear()
		user.send_keys(username)
	def input_password(self,password):
			#对用户名文本框做clear和send_keys操作
		pwd = self.login_page.find_password()
		pwd.clear()
		pwd.send_keys(password)	
	def click_login_btn(self):
		self.login_page.find_login_btn().click()
		
	def get_login_name(self):
		retrun  self.login_page.find_login_name().text
	def get_login_failed_info(self):
		return self.login_page.find_login_failed_info().text
#页面元素操作层
class LoginScenario(object):
    def __init__(self,driver):
        self.login_oper=LoginOper(driver)
    def login(self,username,password):
        self.login_oper.input_username(username)
        self.login_oper.input_password(password)
        self.login_oper.click_login_btn()

重构测试用例

test_001_login.py

from selenium import webdriver
import pytest
from package.pageobject import login_page
data=[('admin','123456','0'),('admin','000000','1')]
@pytest.mark.parametrize(("username","password","status"),data)
class TestLogin():
    def setup(self):
        self.driver=webdriver.Chrome()
        self.driver.maximize_window()
        self.driver.implicitily_wait(20)
        self.driver.get("http://localhost:8080/resouce/login")
    def tearDown(self):
        self.driver.quit()
    def test_001_login(self,username,password,status):
        if status =='0':
        	text=login_page.LoginOper(self.driver).get_failed_info()
            assert text=='无效的用户名或密码'
        elif status =='1':
            text = login_page.LoginOper(self.driver).get_login_name()
            assert usernmae in text
        else:
            print ("参数化的状态只能传入0或1")
测试数据分离

实际工作中遇到两种常见情况:

  1. 同一场景需要增加删除修改数据以覆盖期望的测试场景
  2. 测试数据需要修改,例如之前的账号被同事删除了的场景
测试配置分离
Selenium API封装

二次封装的目的是简化一些复杂的操作,但是千万不要为了封装而封装,因为新封装的方法名对于其他项目的人员来说是比较陌生的。

Base目录下新建一个base.py文件

from selenium.webdriver.support.ui import WebDriverWait
class Base(object):
	def __init__(self,driver):
		self.driver=driver
	def split_locator(self,locator):
		if len(locator.split(',')) ==3:
			by = locator.split(',')[0]#定位器
			value=locator.split(',')[1]+','+locator.split(',')[2]
		else:
			by = locator.split(',')[0]#定位器
			value=locator.split(',')[1]#定位器值
		locator_dict={
		'id':'id',
		'name':'name',
		'tag':'tag name'
		}
		if by not in locator_dict.keys():
			raise NameError("Not can be used")
		return locator_dict[by],value
	def get_element(self,locator,sec=20):
		by,value=self.split_locator(locator)
		try:
			element=WebDriverWait(self.driver,sec,1).until(lambda x:x.find_element(by=by,value=value))
			return element
测试计划

不同的项目有不同的目标,自然也就有不同的自动化测试计划,在做自动化测试计划时,我们需要搞明白以下几个问题:

  1. 项目是全新的项目还是比较稳定的项目
  2. 项目的开发模式是传统瀑布还是快速迭代,对于快速迭代的项目则要求测试团队对版本做出较快的质量评估,单靠人力无法实现,因此自动化测试必不可少
  3. 项目类型为APP还是WEB,对于web项目…
  4. 测试人员比较少,则不宜开展较大规模的自动化测试,因为自动化测试并不能节省测试工作时间
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值