Python3+Selenium实现web自动化测试项目入门

Python3+Selenium3实现web自动化测试项目入门

环境及工具

· 系统:windows 64位
· 开发工具:Python 3
· 自动化测试工具 Selenium3
· 脚本工具 sublime Text3
· 浏览器:Firefox

Selenium作为WebUI自动化测试工具的优势

· 主流且开源
· 支持主流浏览器如Firefox、chrome、IE
· 支持多种开发语言如python、Java、PHP
· 跨平台,支持多种操作系统mac、windows、linux等64位系统
常用的自动化测试工具

安装说明

  1. 安装Python3
  2. 自动化测试环境搭建Selenium3安装:
    (1)下载地址:https://pypi.org/project/selenium/
    (2)在解压好的目录下进行安装 python setup.py install
  3. 安装浏览器驱动
    火狐:https://github.com/mozilla/geckodriver/releases
    下载driver、拷贝到浏览器安装路径、配置环境变量

selenium打开Firefox

from selenium import webdriver
driver = webdriver.Firefox()
driver.get("https://baidu.com")

selenium定位元素的8种方法

  1. 采用ID 属性 :find_element_by_id()
  2. 采用class name属性:find_element_by_class_name()
  3. 采用class name属性:find_element_by_name()

定位到元素后的方法

clear() 清空;send_keys() 输入; back() 后退页面;maximize_windows() 最大化窗口; click() 点击; submit() 提交表单

定位到元素后的属性

tag_name: 标签名
text: 文本内容

  1. 采用tag_name属性:find_element_by_tag_name()
  2. 超链接内容:find_element_by_link_text()
  3. 超链接内容定位,模糊匹配:find_element_by_partial_link_text()
  4. css_selector: find_element_by_css_selector()
    根据CSS属性定位,一般class是用.标记,id是用#标记,定位方式也会比xpath快
    技巧:通过firebug的拷贝css路径
    路径:检查元素-》右键-》复制-》css选择器
  5. xpath: find_element_by_xpath()
    xpath语法

ActionChains模拟用户行为

需要模拟鼠标才能进行的情况,如单击,双击,右击,拖拽等
selenium提供了一个类来处理这类事件selenium.webdriver.common.action_chains.ActionChains(driver)

导入模块

from selenium.webdriver.common.action_chains import ActionChains

调用ActionChains的方法时不会立即执行,会将所有的操作按顺序存放在一个队列里,当调用perform()方法时,队列中的事件会依次执行
如:

ActionChains(driver).click(ele).perform()

事件列表:

perform() 执行链中的所有动作

click(on_element=None) 单击鼠标左键

context_click(on_element=None) 点击鼠标右键

double_click(on_element=None) 双击鼠标左键

move_to_element(to_element) 鼠标移动到某个元素
		
ele.send_keys(keys_to_send) 发送某个词到当前焦点的元素

========== 不常用 ==========

click_and_hold(on_element=None) 点击鼠标左键,不松开

release(on_element=None) 在某个元素位置松开鼠标左键

key_down(value, element=None) 按下某个键盘上的键

key_up(value, element=None) 松开某个键

drag_and_drop(source, target) 拖拽到某个元素然后松开

drag_and_drop_by_offset(source, xoffset, yoffset) 拖拽到某个坐标然后松开

move_by_offset(xoffset, yoffset) 鼠标从当前位置移动到某个坐标

move_to_element_with_offset(to_element, xoffset, yoffset) 移动到距某个元素(左上角坐标)多少距离的位置

send_keys_to_element(element, keys_to_send) 发送某个键到指定元素

网页等待时间

网页需要加载对应的资源文件,页面渲染,窗口处理等等

  1. 强制等待:
from time import sleep   
sleep(5)  # 强制等待5秒再执行下一步,缺点是不管资源是不是完成,都必须等待
  1. 隐性等待:
    设置了一个最长等待时间,如果在规定时间内网页加载完成,则执行下一步,否则一直等到时间截止,然后执行下一步。弊端就是程序会一直等待整个页面加载完成,到浏览器标签栏那个加载圈不再转
    注意:对driver起作用,所以只要设置一次即可,没有必要到处设置,在unittest框架中放入Test_setUp()中
driver.implicitly_wait(10)  # 隐性等待,最长等10秒
  1. 显性等待:
    WebDriverWait 需要配合 until和until_not,程序每隔N秒检查一次,如果成功,则执行下一步,否则继续等待,直到超过设置的最长时间
    语法:WebDriverWait(driver, timeout, poll_frequency=0.5, ignored_exceptions=None)
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

url = 'https://baidu.com'
# url = 'https://www.tmall.com'
# 拿到diver
driver = webdriver.Firefox()


# 跳转网页
driver.get(url)
# print(driver.title) # 使用python判断网页名称是否正确

try:
	# 显性等待
    search_ele = WebDriverWait(driver,5,0.5).until(EC.presence_of_element_located((By.ID,"kw")))
    search_ele.send_keys("小D课堂")
    print("资源加载成功")
    print(driver.title)
except:
	print("资源加载失败,发送报警邮件或短信")
finally:
	print("不管有没有成功,都打印,用于资源清理")
	driver.quit() # 退出

弹窗处理

弹窗常用方法(需要先切换窗口 switch_to_alert() )
accept() 表示接受
dismiss() 表示取消

错误截图

driver.get_screenshot_as_file("./error_png.png")

单元测试unittest

单元测试是指对软件中的最小可测试单元进行检查和验证。对于单元测试中单元的含义,一般来说,要根据实际情况去判定其具体含义。
如C语言中单元指一个函数,Java中指一个类,而图形化的软件可以指一个窗口或菜单。
总的来说单元就是人为规定的最小的被测功能模块。单元测试是在软件开发过程中要进行的最低级别的测试活动,软件的独立单元将在与程序的其他部分相隔离的情况下进行测试。

unittest是python中的单元测试框架
unittest = TestCase + Testresult 执行用例 + 结果

# -*- coding: UTF-8 -*-
# 1、用import语句引入unittest模块
import unittest
# 2、测试的类都继承于TestCase类
class UserTestCase(unittest.TestCase):
    # setUp() 测试前的初始化工作
    # 所有类中方法的入参为self,定义方法的变量也要“self.变量
    def setUp(self):
        pass
    # tearDown()测试后的清除工作
    def tearDown(self):
        pass
    # 定义测试用例,以“test”开头命名的方法,方法的入参为self
    def test_name(self): 
        pass    
if __name__ == '__main__':
    # unittest.main()方法会搜索该模块下所有以test开头的测试用例方法,并自动执行它们
    unittest.main()
    #  输出 成功是 . 失败是 F

TestSuite测试套件

unittest.TestSuite() 类来表示一个测试用例集,用来确定测试用例的顺序,哪个先执行哪个后执行

TextTestRunner(verbosity) 文本测试用例运行器 verbosity参数可以控制执行结果的输出,0 是简单报告、1 是一般报告、2 是详细报告 默认1 会在每个成功的用例前面有个“.” 每个失败的用例前面有个 “F”

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

# -*- coding: UTF-8 -*-
import unittest

class XdclassTestCase(unittest.TestCase):

    def setUp(self):
        self.age = 32
        self.name = "小D课堂"
        print(" setUp method=======")


    def tearDown(self):
        print(" tearDown method=======")
        #断言是否相同
        self.assertEqual('foo'.upper(), 'FOO')


    def test_one(self):        
        print(" test_one 二当家小D 来了")
        #断言是否相同
        self.assertEqual(self.name, "小D课堂",msg="名字不对")


    def test_two(self):
        print(" test_two 前端 来了")
        #断言是否为 true, msg是断言错误的提示信息
        self.assertFalse('XD'.isupper(), msg="不是大写")
        


    def test_three(self):
        print(" test_three 后端 来了")
        self.assertEqual(self.age,32)



    def test_four(self):
        print(" test_four 小D课堂官网上线啦 https://www.xdclass.net")
        self.assertEqual(self.age,32)




if __name__ == '__main__':

    # 利用unittest执行流程测试而非单元测试,需要控制unittest的执行顺序

    # 用unittest.TestSuite()类来表示一个测试用例集,以确定测试用例的执行顺序
    suite = unittest.TestSuite()
    suite.addTest(XdclassTestCase("test_one"))
    suite.addTest(XdclassTestCase("test_two"))
    suite.addTest(XdclassTestCase("test_three"))
    suite.addTest(XdclassTestCase("test_four"))

    # unittest.TextTestRunner()是文本测试用例运行器,通过该类下的run()方法来运行suite所组装的测试用例,入参为suite测试套件
    # verbosity参数可以控制执行结果的输出,0 是简单报告、1 是一般报告(默认)、2 是详细报告
    runner = unittest.TextTestRunner(verbosity=2)
    runner.run(suite)

HTMLTestRunner生成测试报告

HTMLTestRunner 是 Python 标准库的 unittest 模块的一个扩展,它可以生成 HTML的 测试报告,无法通过pip安装。python2和python3,语法不一样,导致HTMLTestRunner在python3不兼容。

# -*- coding: UTF-8 -*-

import unittest
# 导入HTMLTestRunner模块,HTMLTestRunner 是 Python 标准库的 unittest 模块的一个扩展,它可以生成 HTML的 测试报告,无法通过pip安装。 
# 首先要下 HTMLTestRunner.py 文件,将下载的文件放入…\python\Lib目录下 (或者同个路径)
import HTMLTestRunner
import time


class XdclassTestCase(unittest.TestCase):
    def setUp(self):
        self.age = 32
        self.name = "小D课堂"
        print(" setUp method=======")


    def tearDown(self):
        print(" tearDown method=======")
        #断言是否相同
        self.assertEqual('foo'.upper(), 'FOO')


    def test_one(self):
        # 测试用例报告优化,添加说明
        u"登录测试" 

        print(" test_one 二当家小D 来了")
        #断言是否相同
        self.assertEqual(self.name, "小D课堂",msg="名字不对")


    def test_two(self):
        u"跳转测试"
        print(" test_two 前端 来了")
        #断言是否为 true, msg是断言错误的提示信息
        self.assertFalse('XD'.isupper(), msg="不是大写")
        


    def test_three(self):
        print(" test_three 后端 来了")
        self.assertEqual(self.age,32)



    def test_four(self):
        print(" test_four 小D课堂官网上线啦 https://www.xdclass.net")
        self.assertEqual(self.age,32)




if __name__ == '__main__':
    suite = unittest.TestSuite()
    suite.addTest(XdclassTestCase("test_two"))
    suite.addTest(XdclassTestCase("test_one"))
    
    suite.addTest(XdclassTestCase("test_three"))
    suite.addTest(XdclassTestCase("test_four"))

    #verbosity参数可以控制执行结果的输出,0 是简单报告、1 是一般报告(默认)、2 是详细报告
    #runner = unittest.TextTestRunner(verbosity=2)
    #runner.run(suite)

    file_prefix = time.strftime("%Y-%m-%d %H_%M_%S", time.localtime())

    with open('./'+file_prefix+'_result.html','wb') as fp:

        runner = HTMLTestRunner.HTMLTestRunner(stream=fp,title=u'<小D课堂>test report', description=u'用例执行情况:')
        runner.run(suite)



    # #文件名中加了当前时间,每次生成不同的测试报告
    # file_prefix = time.strftime("%Y-%m-%d %H_%M_%S",time.localtime())

    # #创测试报告的result.html文件,此时还是个空文件   
    # #wb 以二进制格式打开一个文件只用于写入。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件
    # fp = open('./'+file_prefix+'_result.html', 'wb')
    # #stream 定义报告所写入的文件;title 为报告的标题;description 为报告的说明与描述
    # runner =HTMLTestRunner.HTMLTestRunner(stream=fp, title=u'<小D课堂>test report', description=u'用例执行情况:')

    # #运行测试容器中的用例,并将结果写入的报告中
    # runner.run(suite)

    # #关闭文件流,将HTML内容写进测试报告文件
    # fp.close()

发送测试报告邮件

from : [email protected] 发件人
to: [email protected] 收件人
subject: hello 主题
body: 欢迎 内容体

邮件传输协议

SMTP协议:全称为 Simple Mail Transfer Protocol,简单邮件传输协议。它定义了邮件客户端软件和SMTP邮件服务器之间,以及两台SMTP邮件服务器之间的通信规则

POP3协议:全称为 Post Office Protocol,邮局协议。它定义了邮件客户端软件和POP3邮件服务器的通信规则

IMAP协议:全称为 Internet Message Access Protocol,Internet消息访问协议,它是对POP3协议的一种扩展,也是定义了邮件客户端软件和IMAP邮件服务器的通信规则

参考资料

#coding=utf-8
import smtplib
import os ,time,datetime
from email.header import Header
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText 



#邮件信息配置. 授权码 xdclass123
sender = '[email protected]'
receiver = '[email protected]' 
auth_code = 'xdclass123'  #设置客户端授权码,不是密码

smtpserver = 'smtp.126.com'
subject = '自动化测试报告'


#读取文件内容
f = open("./result.html", 'rb')
mail_body = f.read()
f.close()



#HTML 形式的文件内容
html = MIMEText(mail_body, _subtype='html', _charset='utf-8')
html['Subject'] = subject
html['from'] = sender
html['to'] = receiver



# html附件 将测试报告放在附件中发送
att1 = MIMEText(mail_body, 'base64', 'gb2312')
att1["Content-Type"] = 'application/octet-stream'
att1["Content-Disposition"] = 'attachment; filename="XdclassTestReport.html"'  # 这里的filename可以任意写



msg = MIMEMultipart()
msg['Subject'] = subject  # 邮件的标题
msg['from'] = sender
msg['to'] = receiver
msg.attach(html)  # 将html附加在msg里
msg.attach(att1)  # 新增一个附件 



#连接 登录 上smtp服务器
smtp = smtplib.SMTP() 
smtp.connect('smtp.126.com') 
smtp.login(sender, auth_code) 

#发送邮件
smtp.sendmail(sender, receiver, msg.as_string()) 
smtp.quit()

如出现以下错误:
smtplib.SMTPDataError: (554, b’DT:SPM 163 smtp9,DcCowAAXV49UMXtfVYYRJw–.35470S2 1601909076,please see http://mail.163.com/help/help_spam_16.htm?ip=123.151.21.189&hostid=smtp9&time=1601909076’)
可能是邮件内容包含未被允许的信息,或被系统识别为垃圾邮件
解决办法:1. 确保发件人和收件人为常用联系人(在列表中),msg中From和To使用发件人和收件人真实邮箱地址
解决链接

实战

需求1:百度登录测试

# coding=utf-8
'''
Created on 2016-7-22
@author: Jennifer
Project:登录百度测试用例
'''
from selenium import webdriver
import unittest, time
from time import sleep
# from selenium.webdriver.common.action_chains import ActionChains

class BaiduLoginTest(unittest.TestCase):

	def setUp(self):
		print("---开始测试---")
		self.driver = webdriver.Firefox()
		self.driver.implicitly_wait(10)
		self.base_url = "https://www.baidu.com/"

	def tearDown(self):
		print("---结束测试---")
		self.driver.quit()

	def test_Login(self):
		u"百度登录测试"
		driver = self.driver
		driver.get(self.base_url)
		# 登录键
		login_ele = driver.find_element_by_css_selector(".s-top-login-btn")
		# 触发点击事件
		login_ele.click()
		# 选择登录方式
		driver.find_element_by_css_selector("#TANGRAM__PSP_11__footerULoginBtn").click()
		# 出现用户名登录界面 输入用户名及密码并登录
		driver.find_element_by_css_selector("#TANGRAM__PSP_11__userName").send_keys("15222629237") # 输入账号
		
		driver.find_element_by_css_selector("#TANGRAM__PSP_11__password").send_keys("330sds3dsd")   # 输入密码
		
		driver.find_element_by_css_selector("#TANGRAM__PSP_11__submit").click()

		# 获取用户名检测是否登录成功
		user_ele = driver.find_element_by_css_selector(".user-name")
		# ActionChains(driver).move_to_element(usern_ele)
		self.assertEqual(user_ele.text,"清dd",msg="登录失败")


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

需求2:有道翻译测试

# coding=utf-8
'''
Created on 2016-7-22
@author: Jennifer
Project: 有道翻译测试用例
'''
from selenium import webdriver
import unittest,time
# from time import sleep
# from selenium.webdriver.common.action_chains import ActionChains

class YoudaoTransTest(unittest.TestCase):

	def setUp(self):
		print("---开始测试---")
		self.driver = webdriver.Firefox()
		self.driver.implicitly_wait(10)
		self.base_url = "http://fanyi.youdao.com/"

	def tearDown(self):
		print("---结束测试---")
		self.driver.quit()

	def test_Trans(self):
		u"有道翻译测试"
		driver = self.driver
		driver.get(self.base_url)
		# 找到输入框输入翻译内容
		driver.find_element_by_css_selector("#inputOriginal").send_keys("你好")
		# 触发点击事件
		# driver.find_element_by_id("transMachine").click()
		trans_ele = driver.find_element_by_css_selector("#transTarget > p:nth-child(1) > span:nth-child(1)")
		print(trans_ele.text)
		self.assertEqual(trans_ele.text,"hello",msg="翻译出错")


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

需求3:整合生成测试报告以邮件发送

# coding=utf-8
'''
Created on 2016-7-22
@author: Jennifer
Project: mail
'''
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.header import Header

class MailUtils():
    # 表示一个类方法,不需要实例化,可以直接调用
    @classmethod
    def send_test_report(cls):

    	# 邮件信息配置,授权码
    	sender = "[email protected]"
    	receiver = "[email protected]"
    	auth_code = "WJLOXWQGBMKGLAQO" #设置客户端授权码,不是密码

    	smtpserver = "smtp.163.com" # 163邮件服务器地址
    	subject = "Web自动化测试报告"

    	# 读取文件内容
    	with open("./result.html","rb") as f:
    		mail_body = f.read()

    	# HTML 形式的邮件内容
    	html = MIMEText(mail_body,_subtype="html",_charset='utf-8')
    	html['Subject'] = subject
    	html['from'] = sender
    	html['to'] = receiver

    	# html附件 将测试报告放在附件中发送
    	att1 = MIMEText(mail_body,'base64','gb2312')
    	att1["Content-Type"] = 'application/octet-stream'
    	att1["Content-Disposition"] = 'attachment; filename="WebTestReport"'

    	msg = MIMEMultipart()
    	msg['Subject'] = subject # 邮件主题
    	msg['from'] = sender
    	msg['to'] = receiver
    	msg.attach(html) # 将html附加在msg里
    	msg.attach(att1) # 新增附件

    	# 连接 登录 上smtp服务器
    	smtp = smtplib.SMTP()
    	smtp.connect("smtp.163.com")
    	smtp.login(sender,auth_code)

    	smtp.sendmail(sender,receiver,msg.as_string())
    	# smtp.sendmail(sender,receiver,html.as_string())
    	smtp.quit()

# coding=utf-8
'''
Created on 2016-7-22
@author: Jennifer
Project: Web测试用例
'''

import unittest,time,HTMLTestRunner
from Baidu_login import BaiduLoginTest
from Youdao_Trans import YoudaoTransTest
from new_mail import MailUtils

# 创建测试集合
def create_suite():

	suite = unittest.TestSuite()
	suite.addTest(unittest.makeSuite(BaiduLoginTest))
	suite.addTest(unittest.makeSuite(YoudaoTransTest))
	return suite

if __name__ == '__main__':
	
	suite = create_suite()

	# 文件名加当前时间
	# file_prefix = time.strftime("%Y-%m-%d %H_%M_%S",time.localtime())

	# with open("./"+file_prefix+"_result.html","wb") as fp:
	with open("./result.html","wb") as fp:
		runner = HTMLTestRunner.HTMLTestRunner(stream=fp,title=u"Web 项目测试报告",description="测试用例执行情况",verbosity=2)
		runner.run(suite)

	MailUtils.send_test_report()

你可能感兴趣的:(软件测试,python,selenium,单元测试,软件测试,sublime,text)