十、UI自动化unittest插件工具
unittest在线安装
在线安装命令
pip install parameterized
pip install HTMLTestReport
以管理员运行命令提示符安装
安装完成后打开PyCharm点击设置
验证查看是否安装成功
测试用例(TestCase)
- 测试用例所在的类, 必须继承自unittest.TestCase
- 每一个测试用例名称, 必须小写的test开头
断言
self.assertEqual(预期结果, 实际结果) # 断言预期结果与实际结果是否相同
# 等同于语法: assert 预期结果 == 实际结果
self.assertIn(预期结果, 实际结果) # 断言预期结果是在实际结果中包含
# 等同于语法: assert 预期结果 in 实际结果
setup和teardown
- setUp和tearDown
- 每个测试用例执行前会自动调用setUp
- 每个测试用例执行后会自动调用tearDown
- setUpClass和tearDownClass
- 这两个方法必须是类方法
- 所有测试用例执行前会自动调用setUpClass
- 所有测试用例执行后会自动调用tearDownClass
# test_01.py
from selenium import webdriver
from selenium.webdriver.common.by import By
import time
import unittest
class TestLogin(unittest.TestCase): # 如果使用unittest, 测试用例所在的类, 一定要继承自TestCase
def setUp(self): # 等同于pytest中的setup, 每个测试用例执行前会自动调用setUp
print("setUp")
def tearDown(self): # 等同于pytest中的teardown, 每个测试用例执行后会自动调用tearDown
print("tearDown")
@classmethod
def setUpClass(cls): # 等同于pytest中的setup_class, 所有测试用例执行前, 自动调用setUpClass
print("setUpClass")
@classmethod
def tearDownClass(cls): # 等同于pytest中的teardown_class, 所有测试用例执行后, 自动调用tearDownClass
print("tearDownClass")
def test_01(self): # 强制规定测试用例的名称, 必须是test开头
driver = webdriver.Chrome()
driver.get("http://hmshop-test.itheima.net/Home/user/login.html")
driver.find_element(By.ID, "username").send_keys("13912121212")
driver.find_element(By.ID, "password").send_keys("111111")
driver.find_element(By.ID, "verify_code").send_keys("8888")
driver.find_element(By.NAME, "sbtbutton").click()
time.sleep(2)
text = driver.find_element(By.CLASS_NAME, "layui-layer-content").text
self.assertEqual("密码错误!", text) # 断言text的值是否为"密码错误!"
driver.quit()
def test_02(self): # 强制规定测试用例的名称, 必须是test开头
driver = webdriver.Chrome()
driver.get("http://hmshop-test.itheima.net/Home/user/login.html")
driver.find_element(By.ID, "username").send_keys("13912121212")
driver.find_element(By.ID, "password").send_keys("123456")
driver.find_element(By.ID, "verify_code").send_keys("1234")
driver.find_element(By.NAME, "sbtbutton").click()
time.sleep(2)
text = driver.find_element(By.CLASS_NAME, "layui-layer-content").text
self.assertEqual("验证码错误", text) # 断言text的值是否为"验证码错误!"
driver.quit()
- 执行测试用例的代码
import unittest
'''
loader = unittest.TestLoader() # 可以自动的查找符合条件的测试用例
suite = loader.discover(".", "test*.py") # 在当前目录查找测试用例, 文件名test开头, 扩展名为py的文件中找
runner = unittest.TextTestRunner() # runner对象的作用是执行测试用例
runner.run(suite) # run方法的作用是执行括号里测试套件中的测试用例
'''
if __name__ == "__main__":
unittest.TextTestRunner().run(unittest.TestLoader().discover(".", "test*.py")) # run方法的作用是执行括号里测试套件中的测试用例
参数化
- 导包from parameterized import parameterized
- 在需要参数化的测试用例前
@parameterized.expand([(参数化用到的实参), (......)])
# test_02.py
from selenium import webdriver
from selenium.webdriver.common.by import By
import time
import unittest
from parameterized import parameterized
class TestLogin(unittest.TestCase):
@parameterized.expand([("13912121212", "111111", "8888", "密码错误!"),
("13912121212", "123456", "1234", "验证码错误")])
def test_01(self, username, password, verify_code, expect):
driver = webdriver.Chrome()
driver.get("http://hmshop-test.itheima.net/Home/user/login.html")
driver.find_element(By.ID, "username").send_keys(username)
driver.find_element(By.ID, "password").send_keys(password)
driver.find_element(By.ID, "verify_code").send_keys(verify_code)
driver.find_element(By.NAME, "sbtbutton").click()
time.sleep(2)
text = driver.find_element(By.CLASS_NAME, "layui-layer-content").text
self.assertEqual(expect, text) # 断言expect与实际结果是否相同
driver.quit()
生成测试报告
import unittest
from htmltestreport import HTMLTestReport
# 实例化TestLoader类为对象loader
loader = unittest.TestLoader()
# 调用loader对象的discover方法, 返回一个测试套件suite, suite中存放的是discover方法找到的所有测试用例
suite = loader.discover(".", "test_02.py")
# 实例化HTMLTestReport类为对象runner, 括号里面是生成测试报告的文件名
runner = HTMLTestReport("./report.html")
# 调用runner对象的run方法, 执行suite中的测试用例
runner.run(suite)
运行测试用例
import unittest
from htmltestreport import HTMLTestReport
suite = unittest.TestLoader().discover("./scripts", "test*.py")
HTMLTestReport("report.html").run(suite)
log处理
import logging
from logging import handlers
class LogTools:
@classmethod
def init_log(cls):
logger = logging.getLogger() # 初始化日志对象
logger.setLevel(logging.INFO) # 设置日志器对应的日志级别
'''
asctime 时间
levelname log级别
name 用户名, 如果在windows上执行, 一般都是root
filename 生成log的py文件名
lineno 在py文件中第几行生成的log信息
message log信息的内容
'''
# 定义控制台处理器
# 在屏幕输出log信息
sh = logging.StreamHandler()
# 定义文件处理器, 下面括号中是log文件的文件名和字符集编码格式
# 把log写入到文件
fh = logging.handlers.TimedRotatingFileHandler("./log/a.log", encoding="UTF-8")
# 定义格式
fmt = "%(asctime)s %(levelname)s %(name)s %(filename)s %(lineno)d %(message)s"
formatter = logging.Formatter(fmt)
# 设置处理器格式
# 把log的格式设置到屏幕对象中
sh.setFormatter(formatter)
fh.setFormatter(formatter)
# 把处理器添加到handler中
logger.addHandler(sh)
# 把log的格式设置到文件对象中
logger.addHandler(fh)
# 输出相对应的级别日志
logger.log_error("error测试")
logger.log_info("info测试")
# 写日志
@classmethod
def log(cls, msg):
logging.info(msg)