python unittest全面解析:
import unittest
import os
class MyUnittest(unittest.TestCase):
def setUp(self) -> None:
print("setUp_每运行一次用例都会执行一次")
self.name = "hi"
print("setUp_name_%s" % self.name)
def tearDown(self) -> None:
print("tearDown_每结束一次用例都会执行一次")
print("tearDown_name_%s" % self.name)
@classmethod
def setUpClass(cls) -> None:
print("setUpClass_整个测试开始后执行,只执行一次")
cls.func = "setUpClass"
print("setUpClass_func_%s" % cls.func)
@classmethod
def tearDownClass(cls) -> None:
print("tearDownClass_整个测试完成后执行,只执行一次")
print("tearDownClass_func_%s" % cls.func)
def test_add(self):
print("测试函数:test_add")
self.name = "test_add"
print("setUpClass_cls.func_%s" % self.func)
def test_subtract(self):
print("测试函数:test_subtract")
self.name = "test_subtract"
self.func = "test_subtract"
if __name__ == "__main__":
# 运行方式一
unittest.main()
执行结果
setUpClass_整个测试开始后执行,只执行一次
setUpClass_func_setUpClass
test_add (ut_module.ut1_test.MyUnittest) ... setUp_每运行一次用例都会执行一次
setUp_name_hi
测试函数:test_add
setUpClass_cls.func_setUpClass
tearDown_每结束一次用例都会执行一次
tearDown_name_test_add
ok
test_subtract (ut_module.ut1_test.MyUnittest) ... setUp_每运行一次用例都会执行一次
setUp_name_hi
测试函数:test_subtract
tearDown_每结束一次用例都会执行一次
tearDown_name_test_subtract
ok
tearDownClass_整个测试完成后执行,只执行一次
tearDownClass_func_setUpClass
----------------------------------------------------------------------
Ran 2 tests in 0.003s
OK
测试分析
结果分析
setUp初始化的值可以改变
setUp_name_hi
测试函数:test_add
setUpClass_cls.func_setUpClass
tearDown_每结束一次用例都会执行一次
tearDown_name_test_add
setUp
中的self.name
的值,在测试函数中是可以被改变的,一开始name
为hi,后面为test_add
setUpClass的的值无法改变
在def setUpClass赋值
self.func = "setUpClass"
在 def test_subtract中赋值
self.func = "test_subtract"
# 执行结果
setUpClass_整个测试开始后执行,只执行一次
setUpClass_func_setUpClass
.....
tearDownClass_整个测试完成后执行,只执行一次
tearDownClass_func_setUpClass
setUpClass
初始化的值在函数中无法改变,应该是cls
和self
的指向不一样
setUp和setUpClass
- 每个用例都要独立,也就是每个用执行时,都会重开设备,就使用
setup
,比如appium
中的driver - 若想复用某个初始化条件,单不期望每个用例都重启再打开,可以使用
setUpClass
- 在使用
appium
时,用setUp
频繁初始化driver
造成执行用例时间太长,可以使用setUpClass
初始化driver,结合launch-app达到每个用例不重启,同时解决依赖关系的问题
- 在使用
不同的运行unittest的方式
方式一
unittest.main()
方式二
# 构造测试集
suite = unittest.TestSuite()
suite.addTest(MyUnittest("test_add"))
suite.addTest(MyUnittest("test_subtract"))
# 执行测试
runner = unittest.TextTestRunner()
runner.run(suite)
方式三
# TestLoader 用来加载TestCase到TestSuite中的,其中有几个 loadTestsFrom__()方法,就是从各个地方寻找TestCase,创建它们的实例,然后add到TestSuite中,再返回一个TestSuite实例
# TestSuite 测试套件集合,最终将传递给testRunner进行测试执行
# TextTestRunner 用来执行测试用例,将测试结果保存在TextTestResult中
# 此用法可以同时测试多个类
suite1 = unittest.TestLoader().loadTestsFromTestCase(MyUnittest)
suite2 = unittest.TestLoader().loadTestsFromTestCase(MyUnittest1)
suite = unittest.TestSuite([suite1, suite2 ])
unittest.TextTestRunner(verbosity=2).run(suite)
方式四
# 进入到测试目录
os.chdir(".//ut_module")
os.system("python -m unittest -v ut1_test")
方式五,直接到终端中输入命令
# 测试某个类下的所有函数
D:\project\ut>python -m unittest -v ut_module.ut1_test
# 测试类中某一个函数
D:\project\ut>python -m unittest -v ut_module.ut1_test.MyUnittest.test_add
# 执行模块下所有test结尾的文件
D:\project\ut>python -m unittest discover D:\project\ut\ut_module "*_test.py"
# 同时执行多个测试类下的测试函数
D:\project\ut>python -m unittest ut_module.ut1_test.MyUnittest.test_add ut_module.ut2_test.MyUnittest.test_subtract1
其他扩展
unittest的条件装饰器的使用
class MyTestCase(unittest.TestCase):
@unittest.skip("demonstrating skipping")
def test_nothing(self):
self.fail("shouldn't happen")
@unittest.skipIf(mylib.__version__ < (1, 3),
"not supported in this library version")
def test_format(self):
# Tests that work for only a certain version of the library.
pass
@unittest.skipUnless(sys.platform.startswith("win"), "requires Windows")
def test_windows_support(self):
# windows specific testing code
pass
def test_maybe_skipped(self):
if not external_resource_available():
self.skipTest("external resource not available")
# test code that depends on the external resource
pass
@unittest.expectedFailure
def test_fail(self):
self.assertEqual(1, 0, "broken")
@unittest.skip("showing class skipping")
class MySkippedTestCase(unittest.TestCase):
def test_not_run(self):
pass
@unittest.skip(reason)
跳过被此装饰器装饰的测试。 reason 为测试被跳过的原因。@unittest.skipIf(condition, reason)
当 condition 为真时,跳过被装饰的测试。@unittest.skipUnless(condition, reason)
跳过被装饰的测试,除非 condition 为真。@unittest.expectedFailure
把测试标记为预计失败。如果测试不通过,会被认为测试成功;如果测试通过了,则被认为是测试失败。exception unittest.SkipTest(reason)
引发此异常以跳过一个测试。
参数化
如果大家对于学习Python有任何问题,学习方法,学习路线,如何学习有效率的问题,可以随时来咨询我,或者缺少系统学习资料的,我做这行年头比较久,自认为还是比较有经验的,可以帮助大家提出建设性建议,这是我的Python交流qun:785128166,有任何问题可以随时来咨询我。
- 在使用
unittest
时,希望testcase
传参给unittest
,下面时用appium
的一个伪代码
class ParametrizedTestCase(unittest.TestCase):
""" TestCase classes that want to be parametrized should
inherit from this class.
"""
def __init__(self, methodName='runTest', param=None):
super(ParametrizedTestCase, self).__init__(methodName)
# 得到testcase传来的参数
global devicess
devicess = param
@classmethod
def setUpClass(cls):
pass
cls.driver = get_driver(devicess)
cls.logTest = myLog().getLog(cls.devicesName) # 每个设备实例化一个日志记录器
def setUp(self):
pass
@classmethod
def tearDownClass(cls):
cls.driver.close_app()
cls.driver.quit()
pass
def tearDown(self):
pass
@staticmethod
def parametrize(testcase_klass, param=None):
testloader = unittest.TestLoader()
testnames = testloader.getTestCaseNames(testcase_klass)
suite = unittest.TestSuite()
for name in testnames:
suite.addTest(testcase_klass(name, param=param))
return suite
class HomeTest(ParametrizedTestCase):
def testFirstOpen(self):
app = {"logTest": self.logTest, "driver": self.driver, "path": PATH("../yamls/home/firstOpen.yaml"),
"device": self.devicesName, "caseName": sys._getframe().f_code.co_name}
page = FirstOpenPage(app)
page.operate()
page.checkPoint()
@classmethod
def setUpClass(cls):
super(HomeTest, cls).setUpClass()
@classmethod
def tearDownClass(cls):
super(HomeTest, cls).tearDownClass()
if __name__ == '__main__':
devices = {"设备信息"}
suite = unittest.TestSuite()
suite.addTest(ParametrizedTestCase.parametrize(HomeTest, param=devices))
unittest.TextTestRunner(verbosity=2).run(suite)