单元测试
unittest是Python自带的单元测试框架,其中最核心的四个概念是:test case, test suite, test runner, test fixture.
流程:TestLoader加载写好的TestCase到TestSuite,由TextTestRunner来运行,并将结果保存在TextTestResult中.通过命令行或unittest.main()执行时,main会调用TextTestRunner中的run来执行
testCase就是一个测试用例,即完整的测试流程,包含测试前环境搭建setUp,执行测试run,断言,测试后环境恢复tearDown.
testSuite多个testCase集合在一起.
testLoader加载testCase到testSuite中,用loadTestsFrom__()方法寻找TestCase,创建实例并添加到TestSuite中返回TestSuite实例.
TextTestRunner用来执行测试用例,其中的run(test)会执行TestSuite/TestCase中的run(result)方法,测试结果保存在TextTestResult中(运行多少,成功多少,失败多少)
test fixture对一个测试用用例环境的搭建和恢复,主要是setUp()和tearDown()
unittest要求单元测试类必须继承 unittest.TestCase,该类中可重写setUp(),tearDown(),setUpClass(),tearDownClasee()四个方法,其他的测试方法需要满足如下要求:
测试方法没有返回值。
测试方法没有任何参数。
测试方法应以test开头
通过命令行python -m unittest TestMyFunc.py执行或调用unittest.main执行:
if name == 'main':
unittest.main()
在unittest中用例默认执行顺序是根据用例名称升序执行而非用例定义的先后顺序执行.自定义执行顺序:
if name == 'main':
tests = [TestMyFunc("test_is_prime"), TestMyFunc("test_add"), TestMyFunc("test_divide")]
suite = unittest.TestSuite()
suite.addTest(tests)
runner = unittest.TextTestRunner()
runner.run(suite)
setUp()和tearDown()是每个test_开头的方法都会在用例执行前和结束后调用一次.setUpClass(cls)和tearDownClass(cls)则是在TestMyFunc.py中执行所有test_开头的方法时才调用.需要用@classmethod
def setUp(self):
print('每个用例执行前调用一次')
@classmethod
def setUpClass(cls):
print('所有用例执行前调用一次)
跳过用例使用skip装饰器,即unittest.skip(reason)无条件跳过,unittest.skipIf(condition,reason)condition为True跳过,unittest.skipUnless(condition,reason)condition为False跳过
@unittest.skipUnless(sys.platform.startwith('linux'), "requires Linux")
def test_divide(self):
...
myfunc.py
def is_prime(num):
if num < 0 or num in (0, 1) or num % 2 == 0:
return False
for ele in range(3, num, 2):
if num % ele == 0:
return False
return True
def add(a, b):
return a + b
def divide(a, b):
return a / b
TestMyFunc.py
import unittest
import PythonScripts.myfunc as my
class TestMyFunc(unittest.TestCase):
"""This is my first testcase, test myfunc.py"""
@classmethod
def setUpClass(cls):
print("每个测试用例执行前会调用setUp()进行环境准备\n")
@classmethod
def tearDownClass(cls):
print("每个测试用例执行后会调用tearDown()来进行恢复\n")
def test_is_prime(self):
"""test the function is_prime()"""
self.assertTrue(my.is_prime(3))
self.assertFalse(my.is_prime(10))
self.assertFalse(my.is_prime(101))
self.assertFalse(my.is_prime(-2))
def test_add(self):
"""test the function add"""
self.assertEqual(10, my.add(4, 6))
self.assertNotEqual(8, my.add(3, 4))
def test_divide(self):
"""test the function divide"""
self.assertEqual(2, my.divide(6, 3))
self.assertNotEqual(3, my.divide(9, -3))
if __name__ == "__main__":
unittest.main(verbosity=2)
做一个简单的小实例:
目录结构如下:
demo1.py
class MyClass():
def __init__(self,x,y):
self.x = x
self.y = y
def add(self):
return self.x + self.y
def sub(self):
return self.x - self.y
import unittest
from unittset_demo.demo1 import MyClass
class MyclassTest(unittest.TestCase):
def setUp(self) -> None:
'''
测试之前的准备工作
:return:
'''
self.clac = MyClass(4,3)
def tearDown(self) -> None:
'''
测试之后的收尾
如关闭数据库
:return:
'''
pass
def test_add(self):
ret = self.clac.add()
self.assertEqual(ret,9)
def test_sub(self):
ret = self.clac.sub()
self.assertEqual(ret,-1)
if __name__ == '__main__':
suite = unittest.TestSuite()
suite.addTest(MyclassTest('test_add'))
suite.addTest(MyclassTest('test_sub'))
runner = unittest.TextTestRunner()
runner.run(suite)
setUp就是帮我们做测试前的准备工作,比如实例化等,
tearDown可以帮我们关闭数据库等收尾操作,
一般测试方法必须以test_开头,里面可以写我们需要测试的业务逻辑,同时指定self.assertEqual()将我们的结果和运行的实际结果进行比对。
suite就是我们的测试集,之后添加测试用例,用runner实例化运行。
运行结果:

如果我们将预计的结果写错,
def test_add(self):
ret = self.clac.add()
self.assertEqual(ret,2)
def test_sub(self):
ret = self.clac.sub()
self.assertEqual(ret,3)
运行结果:

同时我们还可以在django的test文件中测试自己的用例:
class StudentTest(TestCase):
def setUp(self);
Student.objects.create(name='jack',age=13)
def test_student_create(self):
obj = Student.objects.get(name='jack')
self.assertEqual(obj.age,18)
测试是使用的模板是否正确,在terminal中输入:python manage.py test 即可测试
class HomeTest(TestCase):
def test_home_page_renders_home_template(self):
response = self.client.get('/home/') # 模拟浏览器
self.assertEqual(response.status_code,200)
self.assertTemplateUsed(response,'home.html')
浙公网安备 33010602011771号