Web UI自动化测试实例(登入网易云音乐账户)——(三)Python+unittest+selenium+ddt数据驱动_简单版

部署运行你感兴趣的模型镜像

ddt数据驱动

Web UI自动化测试实例(登入网易云音乐账户)——(二)Python+unittest+selenium,实现了测试用例、页面代码分析。
在实际测试中,每个测试用例,需要用多种不同的测试数据进行,是实现测试用例、数据、页面代码分离,提高复用性。此时引入ddt数据驱动

ddt的基本用法:
在测试用例类前面定义@ddt,用于表示要使用ddt了,再基于实际的应用,选择对应的装饰器来使用。
其中:
@data :用于设定参数
@unpack:用于解析参数,unpack不能单独使用,一般跟着data一起使用
@file_data:用于读取文件(json、yaml)中的参数

ddt的数据解析方式:解析一个,传参一个

网易云音乐账户登入实例

测试场景:测试网易云账户登入
测试case:
①输入无效的手机号码+任意密码 ,期望:登入失败,提示请输入正确的手机号
②输入有效的手机号码,且号码已被注册过+错误的密码,期望:登入失败,提示手机号或密码错误 (注意:如果是连续5次登入,则会提示数据次数限制之类的提示语)
测试策略
策略1->用ddt数据驱动中unpack+data实现
策略2->用ddt数据驱动,测试数据放到json文件中,通过file_data实现读取

1. unpack+data

当测试用例中定义了多个需要传值的变量,需要传入多个参数,仅仅使用data,data会将其传入的参数全部当成第一个实参,一一传递到测试用例中,导致测试用例其他形参未传递值,而报错。
data负责获取数据,unpack负责将数据拆分匹配到用例中

测试用例代码,test_login.py

#coding:utf-8
import unittest
from wangyi_music_web import Login_163_Music
from ddt import ddt,data,unpack,file_data

@ddt
class TestLogin(unittest.TestCase):

    @data(('https://music.163.com/','165564999840654','huudff',u'请输入正确的手机号'),('https://music.163.com/','15970456721','mimacuowula',u'该手机号尚未注册')) 
    @unpack
    def test_login_wangyiyun(self,url,phone_number,password,expext_result):
            print ('input phone number:{}'.format(phone_number))
            print ('input password:{}'.format(password))
            print ('expect result:{}'.format(expext_result.encode('utf-8')))
            login = Login_163_Music(url)
            login.click_login()
            login.select_other_login_mode()
            login.check_privacy_policy_checkout()
            login.phone_number_login()
            login.input_phone_number_account(phone_number)
            login.input_password(password)
            login.click_login_button()
            actual_login_result = login.get_actual_login_status()
            #self.assertTrue(expext_result == actual_login_result, 'Test Failed') #断言
            if expext_result.encode('utf-8') == actual_login_result:
                print ('Test Pass')
            else:
                print ('Test Failed,actual_login_result:{}'.format(actual_login_result))
            login.close_window()

if __name__ =='__main__':
    unittest.main()

页面代码,wangyi_music.py

#coding: utf-8
from selenium import  webdriver
from selenium.webdriver.common.by import By
import time

class Login_163_Music():

	_login_locator = (By.CSS_SELECTOR, 'a.link.s-fc3')
	_other_login_mode_locator =(By.CSS_SELECTOR ,'a.u-btn2.other')
	_phone_number_login_locator = (By.CSS_SELECTOR ,'a.u-btn2.u-btn2-2')
	_privacy_policy_checkout_loactor = (By.CSS_SELECTOR ,'input#j-official-terms')
	_input_phone_number_locator = (By.CSS_SELECTOR , 'input.j-phone.txt.u-txt')
	_input_password_locator = (By.CSS_SELECTOR , 'input#pw.j-pwd.u-txt')
	_login_button_locator = (By.CSS_SELECTOR, 'a.j-primary.u-btn2.u-btn2-2')
	_locate_mark_locator = (By.CSS_SELECTOR, 'i.u-icn.u-icn-25')
	_get_login_failed_reason_locator = (By.CSS_SELECTOR,'div.j-err.u-err span')


	def __init__(self,url):
		self.driver = webdriver.Chrome()
		self.driver.implicitly_wait(4)
		self.driver.maximize_window()
		self.driver.get(url)

	def click_login(self):
		self.driver.find_element(*self._login_locator).click()

	def select_other_login_mode(self):
		self.driver.find_element(*self._other_login_mode_locator).click()

	def check_privacy_policy_checkout(self):
		if not self.driver.find_element(*self._privacy_policy_checkout_loactor).is_selected():
			self.driver.find_element(*self._privacy_policy_checkout_loactor).click()

	def phone_number_login(self):	
		self.driver.find_element(*self._phone_number_login_locator).click()

	def input_phone_number_account(self,phone_number):
		self.driver.find_element(*self._input_phone_number_locator).send_keys(phone_number)
	
	def input_password(self,password):
		self.driver.find_element(*self._input_password_locator).send_keys(password)
	
	def click_login_button(self):
		self.driver.find_element(*self._login_button_locator).click()

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

	def get_login_failed_reason(self):#查看页面上登入失败的原因
		#self.driver.implicitly_wait(5)
		time.sleep(3)
		return self.driver.find_element(*self._get_login_failed_reason_locator).text.encode('utf-8')

	def get_actual_login_status(self): #主要是看账户登入真实情况
		if self.driver.find_element(*self._locate_mark_locator).is_displayed: #如果页面上显示出!
			return self.get_login_failed_reason() #打印登入失败的原因
		else:
			return '登入成功' #否则登入成功

测试结果:

input phone number:165564999840654
input password:huudff
expect result:请输入正确的手机号
Test Pass
.input phone number:15970456721
input password:mimacuowula
expect result:该手机号尚未注册
Test Pass
.
----------------------------------------------------------------------
Ran 2 tests in 34.147s

OK

2. json文件+ file_data

当测试数据很多10多组的时候,可以采用将数据放到yaml、json文件中,通过ddt中file_data装饰器去读取数据,本次实例,仅传了2组数据。

测试用例代码,test_login.py

#coding:utf-8
import unittest
from wangyi_music_web import Login_163_Music
from ddt import ddt,data,unpack,file_data

@ddt
class TestLogin(unittest.TestCase):
    
    @file_data('./data.json')
    def test_login_wangyiyun(self,url,phone_number,password,expext_result):
            print ('input phone number:{}'.format(phone_number))
            print ('input password:{}'.format(password))
            print ('expect result:{}'.format(expext_result.encode('utf-8')))
            login = Login_163_Music(url)
            login.click_login()
            login.select_other_login_mode()
            login.check_privacy_policy_checkout()
            login.phone_number_login()
            login.input_phone_number_account(phone_number)
            login.input_password(password)
            login.click_login_button()
            actual_login_result = login.get_actual_login_status()
            #self.assertTrue(expext_result == actual_login_result, 'Test Failed') #断言
            if expext_result == actual_login_result:
                print ('Test Pass')
            else:
                print ('Test Failed,actual_login_result:{}'.format(actual_login_result.encode('utf-8')))
            login.close_window()

if __name__ =='__main__':
    unittest.main()

页面代码,wangyi_music_web.py

#coding: utf-8
from selenium import  webdriver
from selenium.webdriver.common.by import By
import time

class Login_163_Music():
	_login_locator = (By.CSS_SELECTOR, 'a.link.s-fc3')
	_other_login_mode_locator =(By.CSS_SELECTOR ,'a.u-btn2.other')
	_phone_number_login_locator = (By.CSS_SELECTOR ,'a.u-btn2.u-btn2-2')
	_privacy_policy_checkout_loactor = (By.CSS_SELECTOR ,'input#j-official-terms')
	_input_phone_number_locator = (By.CSS_SELECTOR , 'input.j-phone.txt.u-txt')
	_input_password_locator = (By.CSS_SELECTOR , 'input#pw.j-pwd.u-txt')
	_login_button_locator = (By.CSS_SELECTOR, 'a.j-primary.u-btn2.u-btn2-2')
	_locate_mark_locator = (By.CSS_SELECTOR, 'i.u-icn.u-icn-25')
	_get_login_failed_reason_locator = (By.CSS_SELECTOR,'div.j-err.u-err span')


	def __init__(self,url):
		self.driver = webdriver.Chrome()
		self.driver.implicitly_wait(4)
		self.driver.maximize_window()
		self.driver.get(url)

	def click_login(self):
		self.driver.find_element(*self._login_locator).click()

	def select_other_login_mode(self):
		self.driver.find_element(*self._other_login_mode_locator).click()

	def check_privacy_policy_checkout(self):
		if not self.driver.find_element(*self._privacy_policy_checkout_loactor).is_selected():
			self.driver.find_element(*self._privacy_policy_checkout_loactor).click()

	def phone_number_login(self):	
		self.driver.find_element(*self._phone_number_login_locator).click()

	def input_phone_number_account(self,phone_number):
		self.driver.find_element(*self._input_phone_number_locator).send_keys(phone_number)
	
	def input_password(self,password):
		self.driver.find_element(*self._input_password_locator).send_keys(password)
	
	def click_login_button(self):
		self.driver.find_element(*self._login_button_locator).click()

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

	def get_login_failed_reason(self):#查看页面上登入失败的原因
		#self.driver.implicitly_wait(5)
		time.sleep(3)
		return self.driver.find_element(*self._get_login_failed_reason_locator).text

	def get_actual_login_status(self): #主要是看账户登入真实情况
		if self.driver.find_element(*self._locate_mark_locator).is_displayed: #如果页面上显示出!
			return self.get_login_failed_reason() #打印登入失败的原因
		else:
			return '登入成功' #否则登入成功

文件数据,data.json

{
	"test1":{"url":"https://music.163.com/","phone_number":"14654948946456","password":"458496","expext_result":"请输入正确的手机号"},
	"test2":{"url":"https://music.163.com/","phone_number":"18070496814","password":"hahaha","expext_result":"手机号或密码错误"}
}

测试结果:
在这里插入图片描述
第二个测试用例失败的原因:我自己对这个手机号码尝试登入了好多次,超过5次后,会有错误超过限制。正常执行,会是pass的。

代码问题以及优化

  1. 部分元素定位时,未加上等待时间,比如:登入失败的原因提示这个元素,需要加入等待,不然可能定位不到,所以加入time.sleep(), 后续会更改成为显示等待
  2. 代码耦合度,页面代码这一块,比较乱,全部写在一个类中。后续会根据不同的页面,采用 page object ,对于每一个页面的元素及其操作进行一一封装
  3. 测试结果输出,对于测试结果没有无更加直观的输出,后续会将每一条测试用例的结果,输出到excel文件里(思考,可能会采用)

您可能感兴趣的与本文相关的镜像

Python3.10

Python3.10

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值