测试用例—testcase
这是
UnitTest
中最重要的概念,测试就是由一个个测试用例组成的,而对于测试框架来说测试用
例就是最底层的东西,就像盖一座房子一样,砖头就是最基础的东西,无论怎么设计和搭建,最终都 是要靠一块块砖头堆砌而成。测试用例既可以是对同一个测试点的不同输入,也可以是对不同测试点 的不同输入,也可以是对多个测试点的组合测试,就看如何设计组合测试用例,但一般适用于前两者
在
UnitTest
模块中,需要通过继承
TestCase
类来构建单元测试用例
class 测试类名(unittest.TestCase):
测试用例
既可以一个测试用例生成一个类,也可以多个测试用例生成一个类,考虑到执行效率的问题,
建议使用后者来构建测试用例
class 测试类名(unittest.TestCase):
测试用例 1
测试用例 2
测试用例 3
…
一个测试用例可以通过定义一个函数完成,将执行测试的代码封装到函数内,最后通过
TaseCase
类中的断言来判断测试是否通过,常用的断言方法有以下几种。
assertEqual
(预期值,实际值)当两者相等的时候测试通过。
assertNotEqual
(预期值,实际值)当两者不相等的时候测试通过。
assertTrue
(表达式)当表达式为真的时候测试通过。
assertFalse
(表达式)当表达式为假的时候测试通过。
举个简单测试登录接口的例子,通过不同的输入来获取结果,然后用断言判断预期结果和实
际结果是否相等。
实例代码:
1 import unittest#导入 UnitTest 模块
2 import requests
3 class logintest(unittest.TestCase):#定义一个 logintest 的测试类,这个类继承了 UnitTest 的 TestCase 的基类,这样就完成了 UnitTest的一个测试实例,这个实例可以包含多个测试用例,通过函数来完成每一个测试用例
4 def testlogin1(self):#定义 testlogin1()函数作为一个测试用例,该用例测试是否正常登录,即通过输入正确的账号和密码登录,增加断言判断是不是返回的信息“登录成功”,如果是,则测试用例通过,如
果不是,则测试用例不通过
5 url = "http://www.xxx.com/login.html"
6 form = {"username":13111111111,"password":123456}
7 r = requests.post(url,data = form)
8 self.assertEqual(r.text,"登录成功")
9 def testlogin2(self):#定义 testlogin2()函数作为一个测试用例,该用例测试异常登录,即通过空的账号和正确的密码登录,增加断言判断返回的是不是报错信息“用户名不能为空”,如果是,则测试用例
通过,如果不是,则测试用例不通过
10 url = "http://www.xxx.com/login.html"
11 form = {"username":"","password":123456}
12 r = requests.post(url,data = form)
13 self.assertEqual(r.text,"用户名不能为空")
14 def testlogin3(self):#定义 testlogin3()函数作为一个测试用例,该用例测试异常登录,即通过正确的账号和空的密码登录,增加断言判断返回的是不是报错信息“密码不能为空”,如果是,则测试用例通
过,如果不是,则测试用例不通过
15 url = "http://www.xxx.com/login.html"
16 form = {"username":13111111111,"password":""}
17 r = requests.post(url,data = form)
18 self.assertEqual(r.text,"密码不能为空")
19 def testlogin4(self):#定义 testlogin4()函数作为一个测试用例,该用例测试异常登录,即通过正确的账号和错误的密码登录,增加断言判断返回的是不是报错信息“账号或者密码错误”,如果是,则测试
用例通过,如果不是,则测试用例不通过
20 url = "http://www.xxx.com/login.html"
21 form = {"username":13111111111,"password":111111}
22 r = requests.post(url,data = form)
23 self.assertEqual(r.text,"账号或者密码错误")
测试固件—testfixture
测试固件从名字来说就是固定的测试代码,对于测试代码来说必然会有一些相同的部分,比
如测试一个接口,那接口地址就是相同的部分,而这可以通过
setup()
进行初始化,然后各个测试
用例直接调用初始化的接口地址就可以简化代码了。同样还可以通过
teardown()
来结束测试工作。
测试固件就是整合了代码的公共部分
通过上一节的例子会发现,每个测试用例 中的 URL
都是相同的,通过测试固 件的 setup()
可以将
URL
初始化,然后可以给各个测试用例调用。这样可以减少重复的代码, 而且对于以后修改代码也有好处,只需要修改初始化的 URL
,而不需要再对每一个测试用例中的 URL 进行修改,那就把代码改一下。
实例代码:
1 import unittest
2 import requests
3 class logintest(unittest.TestCase):
4 def setUp(self):#在 logintest 类中定义 setUp 函数,这个函数就是放置测试用例的公共部分,类似一个全局变量,供其他函数调用。这里就是初始化一个接口的 URL,让其他函数不需要再重复定义,直
接通过变量 self.url 调用
5 self.url = "http://www.xxx.com/login.html"
6 def testlogin1(self):
7 form = {"username":13111111111,"password":123456}
8 r = requests.post(self.url,data = form)
9 self.assertEqual(r.text,"登录成功")
10 def testlogin2(self):
11 form = {"username":"","password":123456}
12 r = requests.post(self.url,data = form)
13 self.assertEqual(r.text,"用户名不能为空")
14 def testlogin3(self):
15 form = {"username":13111111111,"password":""}
16 r = requests.post(self.url,data = form)
17 self.assertEqual(r.text,"密码不能为空")
18 def testlogin4(self):
19 form = {"username":13111111111,"password":111111}
20 r = requests.post(self.url,data = form)
21 self.assertEqual(r.text,"账号或者密码错误")
因为这是一个简单的测试实例,所以看上去代码只减少了
2
行,但对于公共部分比较多的情
况就会发现减少了很多冗余的代码,也易于后期的维护,因此能利用测试固件的时候尽量使用
测试套件—testsuite
测试套件把多个测试用例集 合到一起,而测试套件和测试用例一样,也可以有多个,并且可以组合在一起形成更多的测试用例集合
完成了测试用例的准备部分,接着需要根据用例进行组合,这时候就用到测试套件了。测试
套件有多种添加测试用例的方式,下面介绍
2
种常用的添加方式。
第一种:
1 import unittest
2 import requests
3 class logintest(unittest.TestCase):
省略之前的代码
4 def suite():#定义一个 suite()函数,用来返回已经创建好的测试套件实例
5 loginTestCase = unittest.TestSuite()#调用 TestSuite()函数生成一个测试套件实例
6 loginTestCase.addTest(logintest("testlogin1"))#使用实例的 addTest 的方法,将 logintest 中的测试函数加入到测试套件中
7 loginTestCase.addTest(logintest("testlogin2"))
8 loginTestCase.addTest(logintest("testlogin3"))
9 loginTestCase.addTest(logintest("testlogin4"))
10 return loginTestCase#返回添加完测试用例的测试套件实例
这样在完成了将测试用例加入到测试套件之中的过程,但这样一个个添加测试用例的方式有
点烦琐,一旦用例太多就会有太多冗余的代码,于是介绍另外一个添加测试用例的方法,通过
makeSuite
方法来创建测试用例类中所有测试用例的测试套件
实例代码:
1 import unittest
2 import requests
3 class logintest(unittest.TestCase):
省略测试用例的代码
4 def suite():
5 loginTestCase = unittest.makeSuite(logintest,"test")#通过 makeSuite()函数将 logintest 中所有 test 开头的测试用例加入测试套件中。
6 return loginTestCase
只需要一行代码就能添加全部的测试用例到测试套件中,但缺点在于不灵活,只能添加全部,
当然如果在测试类中定义所有需要运行的测试用例,那用这个方法就相当简单了。
多个测试套件其实还可以通过
TestSuite
组合在一起,变成一个新的测试套件,来看一下如何
实现。
1 import unittest
2 import requests
3 class logintest(unittest.TestCase):
省略测试用例的代码
4 class loginouttest(unittest.TestCase):
省略测试用例的代码
5 def suite():
6 loginTestCase = unittest.makeSuite(logintest,"test")#先把 2 个测试类的测试用例分别加入 2 个测试套件之中,然后通过 TestSuite 方法把 2个测试套件合成一个测试套件实例
7 loginoutTestCase = unittest.makeSuite(logintest,"test")
8 alltest = unittest.TestSuite(loginTestCase, loginoutTestCase)
9 return alltest
测试运行器—testrunner
测试运行器是给测试用例提供运行环境的,通过它的
run()
方法来执行测试用例,并在执行完
成后将测试结果输出
UnitTest
模块提供了
TestRunner
类,为测试的运行提供了环境,最常见的就是
TextTestRunner
类,整个类使用了文字化的运行方式来报告最后的测试结果,来看例子
2 import requests
3 class logintest(unittest.TestCase):
省略测试用例的代码
4 class loginouttest(unittest.TestCase):
省略测试用例的代码
5 def suite():
省略测试套件的代码
6 if __name__ == "__main__":
7 runner = unittest.TextTestRunner()#使用 TextTestRunner 类构建一个运行器对象,此对象提供了 run 方法,它所接收的参数是之前生成的测试套件实例,这样测试框架就可以自动运行测试套件中的测试用例了
8 runner.run(suite())
执行结果
其实还有一个更简单的运行方法,就是用
UnitTest
的
main
方法,这个方法是一个全局方法,
即直接加载所有测试类中的测试用例,并全部执行,只需要一句代码就行。
1 import unittest
2 import requests
3 class logintest(unittest.TestCase):
省略测试用例的代码
4 class loginouttest(unittest.TestCase):
省略测试用例的代码
5 def suite():
省略测试套件的代码
6 if __name__ == "__main__":
7 unittest.main()#用 main 方法完成所有测试用例的加载和运行,就是将所有的操作封装在 main 方法之中。结果和之前是一样的,这个方法虽然方便,却少了一些灵活性,需要通过实际情况来选择使用
测试报告
UnitTest
测试框架作为
Python
内置的框架,也并非十分完善,虽然运行测试框架能看到结果,
但没有测试报告的输出,不易于测试结果的保存。那要如何获取测试报告呢?需要下载导入一个
第三方模块
HTMLTestRunner
,这个类区别于之前的
TextTestRunner
类,是以
HTML
形式存放测
试结果的,并会以报告的形式保存。
2 import requests
3 import HTMLTestRunner
4 class logintest(unittest.TestCase):
省略测试用例的代码
5 class loginouttest(unittest.TestCase):
省略测试用例的代码
6 def suite():
省略测试套件的代码
7 if __name__ == "__main__":
8 fr = open("res1.html","wb")#新建一个名为 res1.html 的 HTML,并且设置权限是读写,description="详情")
9 runner = HTMLTestRunner.HTMLTestRunner(stream=fr,title=“"测试报告"#使用 HTMLTestRunner 模块中的 HTMLTestRunner 方法,构建一个运行器对象,并通过参数将结果写入之前新建的 res1.html 文件之中,标题为测试报告,描述为详情,最后也是通过 run方法完成测试用例的运行
10 runner.run(suite())