什么是unittest?
unittest是python的单元测试框架,unittest单元测试提供了创建测试用例,测试套件,以及批量执行的方案,在使用unittest时,直接引入unittest包就可以使用。
unittest各组件的关系:
1.test fixture:初始化和清理测试环境,比如创建临时的数据库,文件和目录等,其中setUp()和tearDown()是最常用的方法
2.test case:单元测试用例,TestCase是编写单元测试用例最常用的类
3.test suit:单元测试用例的集合,TestSuit是最常用的类
4.test runner:执行单元测试
5.test report:生成测试报告
批量执行脚本
一.构建测试套件
完整的测试单元很少执行一个测试用例,开发人员通常是编写多个测试用例才能对某一个功能进行比较完整的测试,这些相关的测试用例称为一个测试用例集。
举例:有两个编写好的测试脚本
testbaidu1.py
from selenium import webdriver
import unittest
class Baidu1(unittest.TestCase):
def setUp(self):
self.driver=webdriver.Firefox()
self.driver.implicitly_wait(30)
self.base_url="https://www.baidu.com/"
self.verificationErrors=[]
self.accept_next_alert=True
def test_baidusearch(self):
driver=self.driver
driver.get(self.base_url+"/")
driver.find_element_by_id("kw").click()
driver.find_element_by_id("kw").clear()
driver.find_element_by_id("kw").send_keys("unittest")
driver.find_element_by_id("su").click()
def test_hao(self):
driver = self.driver
driver.get(self.base_url + "/")
driver.find_element_by_link_text("hao123").click()
self.assertEqual(u"hao123_上网从这里开始",driver.title)
def tearDown(self):
self.driver.quit()
if __name__ == "__main__":
unittest.main()
testbaidu2.py
from selenium import webdriver
import unittest
class Baidu2(unittest.TestCase):
def setUp(self):
self.driver = webdriver.Firefox()
self.driver.implicitly_wait(30)
self.base_url = "https://www.baidu.com/"
self.verificationErrors = []
self.accept_next_alert = True
def test_baidusearch(self):
driver = self.driver
driver.get(self.base_url + "/")
driver.find_element_by_id("kw").click()
driver.find_element_by_id("kw").clear()
driver.find_element_by_id("kw").send_keys("测试2")
driver.find_element_by_id("su").click()
def tearDown(self):
self.driver.quit()
if __name__ == "__main__":
unittest.main()
如上述有两个测试脚本,如何同时执行脚本里的方法呢?
1.利用addTest()
当有很多测试用例的时候,这样就要有一个测试容器,将所有的测试用例放在该容器中进行执行,unittest中提供了TestSuit类来生成测试套件,使用该类的构造函数可以生成一个测试套件的实例,提供了addTest来将每个测试用例加入到测试套件中。
runnerall.py
import unittest
import testbaidu1
import testbaidu2
#手工添加案例到套件
def creatsuit():
suite=unittest.TestSuite()
suite.addTest(testbaidu1.Baidu1("test_baidusearch"))
suite.addTest(testbaidu1.Baidu1("test_hao"))
suite.addTest(testbaidu2.Baidu2("test_baidusearch"))
return suite
if __name__=="__main__":
suite=creatsuit()
runner=unittest.TextTestRunner(verbosity=2)
runner.run(suite)
上述代码main中加入verbosity=2,这样测试的结果就会显示的更加详细
0(静默模式):只能获得总的测试用例数和总的结果
1(默认模式):类似静默模式只是在每个成功的用例前面有个“.”,每个失败的前面有个f
2(详细模式):会显示每个测试用例的所有相关信息
运行结果:
但是上述方法有缺陷:
①需要导入所有的py文件,新增一个就要导入一个
②addTest需要增加所有testcase,如果一个py文件中有10个case,那么就需要增加10次
这样效率会很慢,每次都要修改runnerall.py
2.makeSuite()和TestLoader()
在unittest框架中提供了makeSuite()的方法,makeSuite()可以实现把测试用例类内的所有测试套件TestSuite,unittest调用makeSuite时,只需要将测试类名称传入即可
TestLoader用于创建类和模块的测试套件
①使用makeSuite():
import unittest
import testbaidu1
import testbaidu2
#手工添加案例到套件
def creatsuit():
suite=unittest.TestSuite()
suite.addTest(unittest.makeSuite(testbaidu1.Baidu1))
suite.addTest(unittest.makeSuite(testbaidu2.Baidu2))
return suite
if __name__=="__main__":
suite=creatsuit()
runner=unittest.TextTestRunner(verbosity=2)
runner.run(suite)
②使用TestLoader():
import unittest
import testbaidu1
import testbaidu2
#手工添加案例到套件
def creatsuit():
suite1 = unittest.TestLoader().loadTestsFromTestCase(testbaidu1.Baidu1)
suite2 = unittest.TestLoader().loadTestsFromTestCase(testbaidu2.Baidu2)
suite = unittest.TestSuite([suite1, suite2])
return suite
if __name__=="__main__":
suite = creatsuit()
runner = unittest.TextTestRunner(verbosity=2)
runner.run(suite)
经过makeSuit()和TestLoader()的引入,就需要导入一次即可。那么现在能不能测试类也不用每次添加指定呢?
3.discover()
discover是通过递归的方式到其子目录中从指定的目录开始,找到所有测试模块并且返回一个包含他们对象的TestSuite,然后进行加载与模式匹配唯一的测试文件。
在下述代码执行之前先将testbaidu1.py和testbaidu2.py放在新建的test路径下,然后将runnerall.py放在run路径下
参考脚本:
import unittest
#手工添加案例到套件
def creatsuit():
discover = unittest.defaultTestLoader.discover('../test',pattern='test*.py',top_level_dir=None)
print(discover)
return discover
if __name__=="__main__":
suite = creatsuit()
runner = unittest.TextTestRunner(verbosity=2)
runner.run(suite)
注意上述路径:
执行结果:
用例的执行顺序
unittest框架默认加载测试用例的顺序是根据ASCII码的顺序。数字与字母的顺序为:0-9,A-Z,a-z
忽略用例执行
@unittest.skip(u’The function was canceled,neglects to perform thecase’)
参考脚本:
from selenium import webdriver
import unittest
class Baidu1(unittest.TestCase):
def setUp(self):
self.driver=webdriver.Firefox()
self.driver.implicitly_wait(30)
self.base_url="https://www.baidu.com/"
self.verificationErrors=[]
self.accept_next_alert=True
def test_baidusearch(self):
driver=self.driver
driver.get(self.base_url+"/")
driver.find_element_by_id("kw").click()
driver.find_element_by_id("kw").clear()
driver.find_element_by_id("kw").send_keys("unittest")
driver.find_element_by_id("su").click()
@unittest.skip("skipping")
def test_hao(self):
driver = self.driver
driver.get(self.base_url + "/")
driver.find_element_by_link_text("hao123").click()
self.assertEqual(u"hao123_上网从这里开始",driver.title)
def tearDown(self):
self.driver.quit()
if __name__ == "__main__":
unittest.main()
执行结果: 成功跳过被注解的测试用例
unittest断言
unittest的库中提供了大量的实用方法来检查预期值和实际值,来验证case的结果。
一.常用的断言方法:
断言方法 | 断言描述 |
---|---|
assertEqual(arg1,arg2,msg=None) | 验证arg1=arg2,不等则fail |
assertNotEqual(arg1,arg2,msg=None) | 验证两个不相等,相等则fail |
assertTrue(expr,msg=None) | 验证是否为true,如果是false,则fail |
assertFalse(expr,msg=None) | 验证是否为false,如果是true,则fail |
assertls(arg1,arg2,msg=None) | 验证arg1,arg2是同一个对象,不是则fail |
assertlsNot(arg1,arg2,msg=None) | 验证arg1,arg2不是同一个对象,是则fail |
assertlsNone(expr,msg=None) | 验证expr是空,不是则fail |
assertlsNotNone(expr,msg=None) | 验证expr不是空,是则fail |
assertIn(arg1,arg2,msg=None) | 验证arg1是arg2的子串,不是则fail |
assertNotIn(arg1,arg2,msg=None) | 验证arg1不是arg2的子串,是则fail |
assertlsInstance(obj,cls,msg=None) | 验证obj是cls的实例,不是则fail |
assertNotlsInstance(obj,cls,msg=None) | 验证obj不是cls的实例,是则fail |
二.使用IDE录制脚本时也可以添加断言: