unittest
unittest
unittest单元测试框架
TestCase
说明:测试用例
定义测试用例:
导包 import unittest 定义测试类 测试类必须要继承unittest.TestCase class TestLogin(unittest.TestCase) 定义测试方法 方法名必须以小写的test开头
运行测试用例: 在pycharm中点击右键运行(方法体上、类体上) 命令行运行 python 文件名 unittest.main()
TestSuite
说明:测试套件,多个测试用例就可以组合成一个测试套件 实例化测试套件对象 suite = unittest.TestSuite() 添加测试用例 suite.addTest(ClassName("方法名称")) suite.addTest(unittest.makeSuite(ClassName))
TextTestRunner
说明:用来执行测试套件的 实例化对象 runner = unittest.TextTestRunner() 执行测试套件 runner.run(suite)
TestLoader
说明:自动构建测试套件 suite = unittest.TestLoader().discover(测试用例所在的目录, pattern="test*.py")
Fixture
说明:Fixture是一个概述,对一个测试用例环境的初始化和销毁就是一个Fixture Fixture控制级别: 方法级别 类级别 模块级别
方法级别:作用于测试类中所有的测试方法 初始化 def setUp(self): 销毁 def tearDown(self) 类级别:作用于整个测试类,在测试类执行前后执行一次 初始化 @classmethod def setUpClass(cls): 销毁 @classmethod def tearDownClass(cls) 模块级别:作用于整个模块 初始化 def setUpModule(): 销毁 def tearDownModule()
断言
常用的UnitTest断言方法
序号 | 断言方法 | 断言描述 |
---|---|---|
1 | assertTrue(expr, msg=None) | 验证expr是true,如果为false,则fail |
2 | assertFalse(expr, msg=None) | 验证expr是false,如果为true,则fail |
3 | assertEqual(expected, actual,msg=None) | 验证expected==actual,不等则fail |
4 | assertNotEqual(first, second,msg=None) | 验证first != second, 相等则fail |
5 | aassertIsNone(obj, msg=None) | 验证obj是None,不是则fail |
6 | assertIsNotNone(obj, msg=None) | 验证obj不是None,是则fail |
7 | assertIn(member, container,msg=None) | 验证是否member in container |
8 | assertNotIn(member, container,msg=None) | 验证是否member not in container |
参数化
pip install parameterized
data = [(1, 2), (3, 4)]
@parameterized.expand(data)
def test_add(self, x, y)
跳过
对于一些未完成的或者不满足条件的测试方法或测试类可以执行跳过的操作
实现方式: @unittest.skip(跳过的原因) @unittest.skipIf(condition, reason)
示例模板
import time
import unittest
import config
from script.test_cart import Test1
from script.test_login import TestLogin
from tools.HTMLTestRunner import HTMLTestRunner
from utils import DriverUtil
# 关闭自动退出驱动的标记
DriverUtil.set_auto_quit(False)
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestLogin))
suite.addTest(unittest.makeSuite(Test1))
# unittest.TextTestRunner().run(suite)
# 测试报告路径
report_path = config.BASE_PATH + "/report/r{}.html".format(time.strftime("%Y%m%d-%H%M%S"))
with open(report_path, "wb") as f:
runner = HTMLTestRunner(f, title="自动化测试报告", description="Win10. Vxxx")
runner.run(suite)
# 打开自动退出驱动的标记
DriverUtil.set_auto_quit(True)
DriverUtil.quit_driver()
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>自动化测试报告模板</title>
<meta name="generator" content="HTMLTestRunner 0.8.2"/>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<style type="text/css" media="screen">
body { font-family: verdana, arial, helvetica, sans-serif; font-size: 80%; }
table { font-size: 100%; }
pre { }
/* -- heading ---------------------------------------------------------------------- */
h1 {
font-size: 16pt;
color: gray;
}
.heading {
margin-top: 0ex;
margin-bottom: 1ex;
}
.heading .attribute {
margin-top: 1ex;
margin-bottom: 0;
}
.heading .description {
margin-top: 4ex;
margin-bottom: 6ex;
}
/* -- css div popup ------------------------------------------------------------------------ */
a.popup_link {
}
a.popup_link:hover {
color: red;
}
.popup_window {
display: none;
position: relative;
left: 0px;
top: 0px;
/*border: solid #627173 1px; */
padding: 10px;
background-color: #E6E6D6;
font-family: "Lucida Console", "Courier New", Courier, monospace;
text-align: left;
font-size: 8pt;
width: 500px;
}
}
/* -- report ------------------------------------------------------------------------ */
#show_detail_line {
margin-top: 3ex;
margin-bottom: 1ex;
}
#result_table {
width: 80%;
border-collapse: collapse;
border: 1px solid #777;
}
#header_row {
font-weight: bold;
color: white;
background-color: #777;
}
#result_table td {
border: 1px solid #777;
padding: 2px;
}
#total_row { font-weight: bold; }
.passClass { background-color: #6c6; }
.failClass { background-color: #c60; }
.errorClass { background-color: #c00; }
.passCase { color: #6c6; }
.failCase { color: #c60; font-weight: bold; }
.errorCase { color: #c00; font-weight: bold; }
.hiddenRow { display: none; }
.testcase { margin-left: 2em; }
/* -- ending ---------------------------------------------------------------------- */
#ending {
}
</style>
</head>
<body>
<script language="javascript" type="text/javascript"><!--
output_list = Array();
/* level - 0:Summary; 1:Failed; 2:All */
function showCase(level) {
trs = document.getElementsByTagName("tr");
for (var i = 0; i < trs.length; i++) {
tr = trs[i];
id = tr.id;
if (id.substr(0,2) == 'ft') {
if (level < 1) {
tr.className = 'hiddenRow';
}
else {
tr.className = '';
}
}
if (id.substr(0,2) == 'pt') {
if (level > 1) {
tr.className = '';
}
else {
tr.className = 'hiddenRow';
}
}
}
}
function showClassDetail(cid, count) {
var id_list = Array(count);
var toHide = 1;
for (var i = 0; i < count; i++) {
tid0 = 't' + cid.substr(1) + '.' + (i+1);
tid = 'f' + tid0;
tr = document.getElementById(tid);
if (!tr) {
tid = 'p' + tid0;
tr = document.getElementById(tid);
}
id_list[i] = tid;
if (tr.className) {
toHide = 0;
}
}
for (var i = 0; i < count; i++) {
tid = id_list[i];
if (toHide) {
document.getElementById('div_'+tid).style.display = 'none'
document.getElementById(tid).className = 'hiddenRow';
}
else {
document.getElementById(tid).className = '';
}
}
}
function showTestDetail(div_id){
var details_div = document.getElementById(div_id)
var displayState = details_div.style.display
// alert(displayState)
if (displayState != 'block' ) {
displayState = 'block'
details_div.style.display = 'block'
}
else {
details_div.style.display = 'none'
}
}
function html_escape(s) {
s = s.replace(/&/g,'&');
s = s.replace(/</g,'<');
s = s.replace(/>/g,'>');
return s;
}
/* obsoleted by detail in <div>
function showOutput(id, name) {
var w = window.open("", //url
name,
"resizable,scrollbars,status,width=800,height=450");
d = w.document;
d.write("<pre>");
d.write(html_escape(output_list[id]));
d.write("\n");
d.write("<a href='javascript:window.close()'>close</a>\n");
d.write("</pre>\n");
d.close();
}
*/
--></script>
<div class='heading'>
<h1>TPshop自动化测试报告</h1>
<p class='attribute'><strong>Start Time:</strong> 2019-05-18 16:46:21</p>
<p class='attribute'><strong>Duration:</strong> 0:00:32.756413</p>
<p class='attribute'><strong>Status:</strong> Pass 2</p>
<p class='description'>Win10. Vxxx</p>
</div>
<p id='show_detail_line'>Show
<a href='javascript:showCase(0)'>Summary</a>
<a href='javascript:showCase(1)'>Failed</a>
<a href='javascript:showCase(2)'>All</a>
</p>
<table id='result_table'>
<colgroup>
<col align='left' />
<col align='right' />
<col align='right' />
<col align='right' />
<col align='right' />
<col align='right' />
</colgroup>
<tr id='header_row'>
<td>Test Group/Test case</td>
<td>Count</td>
<td>Pass</td>
<td>Fail</td>
<td>Error</td>
<td>View</td>
</tr>
<tr class='passClass'>
<td>script.test_login.TestLogin</td>
<td>1</td>
<td>1</td>
<td>0</td>
<td>0</td>
<td><a href="javascript:showClassDetail('c1',1)">Detail</a></td>
</tr>
<tr id='pt1.1' class='hiddenRow'>
<td class='none'><div class='testcase'>test_login_0_13012345678</div></td>
<td colspan='5' align='center'>pass</td>
</tr>
<tr class='passClass'>
<td>script.test_cart.TestCart</td>
<td>1</td>
<td>1</td>
<td>0</td>
<td>0</td>
<td><a href="javascript:showClassDetail('c2',1)">Detail</a></td>
</tr>
<tr id='pt2.1' class='hiddenRow'>
<td class='none'><div class='testcase'>test_add_goods_to_cart</div></td>
<td colspan='5' align='center'>pass</td>
</tr>
<tr id='total_row'>
<td>Total</td>
<td>2</td>
<td>2</td>
<td>0</td>
<td>0</td>
<td> </td>
</tr>
</table>
<div id='ending'> </div>
</body>
</html>