python接口测试框架实战与自动化进阶
一、fiddler在工作中的运用
1、如何抓接口
抓紧手机端接口
①、在电脑终端输入:ipconfig ,找到电脑ip
②、打开手机,连接WiFi,进入WiFi详情,改用手动代理,将ip设置为电脑端的ip,端口默认(8888)
③、打开fiddler,找到并打开Fiddler Options ,选择Connections栏,做如下改动:
这样就可以尝试抓取接口了。
注:Python requests中文文档参考:http://docs.python-requests.org/zh_CN/latest/user/quickstart.html
二、unittest使用
python自带的包
1、unittest简单使用
使用unittest的test类:TestCase ,重载相关方法:
import unittest class TestMethod(unittest.TestCase): @classmethod def setUpClass(cls): print('重载setUpClass类方法,类实例化(初始化)时调用') @classmethod def tearDownClass(cls): print('重载tearDownClass方法,所有方法执行完后调用') def setUp(self): print('重载setUp方法,每个test方法执行前都会调用') def tearDown(self): print('重载tearDown方法,每个test方法执行完成后都会调用') def test_01(self): print('测试方法,必须以 test 开头') if __name__ == '__main__': unittest.main()
2、unittest基本介绍
参考:http://www.php.cn/python-tutorials-358252.html
unittest提供了多个类:
__all__ = ['TestResult', 'TestCase', 'TestSuite', 'TextTestRunner', 'TestLoader', 'FunctionTestCase', 'main', 'defaultTestLoader', 'SkipTest', 'skip', 'skipIf', 'skipUnless', 'expectedFailure', 'TextTestResult', 'installHandler', 'registerResult', 'removeResult', 'removeHandler']
TestCase
setUp() # 在每个test执行前都要执行的方法 tearDown() #在每个test执行后都要执行的方法。(不管是否执行成功) setUpClass() # 在一个测试类中在所有test开始之前,执行一次且必须使用到Testsuite(只有在TestSuite的run方法里面才对其调用) tearDownClass() # 在一个测试类中在所有test结束之后,执行一次且必须使用到Testsuite(只有在TestSuite的run方法里面才对其调用) run() # 这是unnitest的核心,逻辑也相对复杂,但是很好理解,具体自己看源码。所有最终case的执行都会归结到该run方法 # 还有一个重要的_resultForDoCleanups私有变量,存储TestResult的执行结果,这个在构建后面的skip用到
我们要明确TestCase类中所有的测试用例是独立的,其实每个testcase就是一个个TestCase类的实例对象,所以不要企图在某个test存储或改变一个变量,下个test中能用到,除非利用到setUpClass。我们看个例子:
import unittest class Mydemo(unittest.TestCase): def test1(self): self.a=1 print ("i am test1 the value of a is {}".format(self.a)) def test2(self): print ("i am test2 the value of a is {}".format(self.a)) if __name__ == '__main__': unittest.main()
打印结果:
C:\Python27\python.exe D:/Moudle/module_1/test4.py i am test1 the value of a is 1 .E ====================================================================== ERROR: test2 (__main__.Mydemo) ---------------------------------------------------------------------- Traceback (most recent call last): File "D:/Moudle/module_1/test4.py", line 7, in test2 print ("i am test2 the value of a is {}".format(self.a)) AttributeError: 'Mydemo' object has no attribute 'a' ---------------------------------------------------------------------- Ran 2 tests in 0.001s FAILED (errors=1)
上面就是说明TestCase类中所有的测试用例是独立的,每个testcase就是由TestCase实例化的一个独立的实例。如果要使用共享变量,使用全局变量或者类变量就好了。
借用类方法setUpClass与tearDownClass只执行一遍的特性,实现个小例子:启动时开启浏览器,执行结束时关闭浏览器:
import unittest from selenium import webdriver class Mydemo(unittest.TestCase): @classmethod def setUpClass(cls): cls.browser=webdriver.Firefox() def test1(self): '''登录''' browser=self.browser #do someting about login def test2(self): '''查询''' browser = self.browser # do someting about search def test3(self): '''提交数据''' browser = self.browser # do someting about submmit @classmethod def tearDownClass(cls): browser=cls.browser browser.close() if __name__ == '__main__': unittest.main()
一个class继承了unittest.TestCase,便是一个测试用例,但如果其中有多个以 test 开头的方法,那么每有一个这样的方法,在load的时候便会生成一个TestCase实例,如:一个class中有四个test_xxx方法,最后在load到suite中时也有四个测试用例。整个流程:
1、写好TestCase
2、然后由TestLoader加载TestCase到TestSuite
3、然后由TextTestRunner来运行TestSuite,运行的结果保存在TextTestResult中
4、我们通过命令行或者unittest.main()执行时,main会调用TextTestRunner中的run来执行,或者我们可以直接通过TextTestRunner来执行用例
这里加个说明,在Runner执行时,默认将执行结果输出到控制台,我们可以设置其输出到文件,在文件中查看结果(测试报告)
demo:
# test_mathfunc.py import unittest from mathfunc import * class TestMathFunc(unittest.TestCase): """Test mathfuc.py""" def test_add(self): """Test method add(a, b)""" self.assertEqual(3, add(1, 2)) self.assertNotEqual(3, add(2, 2)) def test_minus(self): """Test method minus(a, b)""" self.assertEqual(1, minus(3, 2)) def test_multi(self): """Test method multi(a, b)""" self.assertEqual(6, multi(2, 3)) def test_divide(self): """Test method divide(a, b)""" self.assertEqual(2, divide(6, 3)) self.assertEqual(3, divide(5, 2)) if __name__ == '__main__': unittest.main()
执行结果:
.F.. ====================================================================== FAIL: test_divide (__main__.TestMathFunc) Test method divide(a, b) ---------------------------------------------------------------------- Traceback (most recent call last): File "E:/AutomaticTest/Test_Framework/temp/test_mathfunc.py", line 24, in test_divide self.assertEqual(3, divide(5, 2)) AssertionError: 3 != 2.5 ---------------------------------------------------------------------- Ran 4 tests in 0.001s FAILED (failures=1)
能够看到一共运行了4个测试,失败了1个,并且给出了失败原因,3 != 2.5
这就是一个简单的测试,有几点需要说明的:
- 在第一行给出了每一个用例执行的结果的标识,成功是 .,失败是 F,出错是 E,跳过是 S。从上面也可以看出,测试的执行跟方法的顺序没有关系,test_divide写在了第4个,但是却是第2个执行的。
- 每个测试方法均以 test 开头,否则是不被unittest识别的。
- 在unittest.main()中加 verbosity 参数可以控制输出的错误报告的详细程度,默认是 1,如果设为 0,则不输出每一用例的执行结果,即没有上面的结果中的第1行;如果设为 2,则输出详细的执行结果,如下:
# if __name__ == '__main__': # unittest.main(verbosity=2) # 输出结果: test_add (__main__.TestMathFunc) Test method add(a, b) ... ok test_divide (__main__.TestMathFunc) Test method divide(a, b) ... FAIL test_minus (__main__.TestMathFunc) Test method minus(a, b) ... ok test_multi (__main__.TestMathFunc) Test method multi(a, b) ... ok ====================================================================== FAIL: test_divide (__main__.TestMathFunc) Test method divide(a, b) ---------------------------------------------------------------------- Traceback (most recent call last): File "E:/AutomaticTest/Test_Framework/temp/test_mathfunc.py", line 24, in test_divide self.assertEqual(3, divide(5, 2)) AssertionError: 3 != 2.5 ---------------------------------------------------------------------- Ran 4 tests in 0.001s FAILED (failures=1)
批量测试TestCase:
1)不用 unittest.main() 执行,直接通过TextTestRunner来执行用例
import unittest from test_mathfunc import TestMathFunc if __name__ == '__main__': suite = unittest.TestSuite() tests = [TestMathFunc("test_add"), TestMathFunc("test_minus"), TestMathFunc("test_divide")] suite.addTests(tests) # 将每个case用例都添加到TestSuite中 runner = unittest.TextTestRunner(verbosity=2) runner.run(suite) # 使用 TextTestRunner执行案例,默认结果会输出倒控制台
2)上述是使用addTest方法添加单个TestCase用例到TestSuite列表中,另外还能使用addTests + TestLoader 添加TestCase用例到TestSuite中
# 直接用addTest方法添加单个TestCase suite.addTest(TestMathFunc("test_multi")) # 使用addTests + unittest.TestLoader()方法结合 # loadTestsFromName(),传入'模块名.TestCase名' suite.addTests(unittest.TestLoader().loadTestsFromName('test_mathfunc.TestMathFunc')) suite.addTests(unittest.TestLoader().loadTestsFromNames(['test_mathfunc.TestMathFunc'])) # loadTestsFromNames(),类似,传入列表 # loadTestsFromTestCase(),传入TestCase suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestMathFunc))
需要注意的是:用TestLoader的方法是无法对case进行排序的。同时,suite中也可以套suite。
将测试结果输出到文件中
用例组织好了,但结果只能输出到控制台,这样没有办法查看之前的执行记录,我们想将结果输出到文件
import unittest from test_mathfunc import TestMathFunc # TestCase用例 if __name__ == '__main__': suite = unittest.TestSuite() suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestMathFunc)) with open(r'D:\UnittestTextReport.txt', 'a') as f: runner = unittest.TextTestRunner(stream=f,verbosity=2) # 将结果输出到D盘下的 UnittestTextReport.txt 文件中 runner.run(suite)
跳过case
unittest也提供了几种方法,用于临时跳过某个case不执行
1)skip装饰器
import unittest from mathfunc import * class TestMathFunc(unittest.TestCase): """Test mathfuc.py""" def test_add(self): """Test method add(a, b)""" self.assertEqual(3, add(1, 2)) self.assertNotEqual(3, add(2, 2)) def test_minus(self): """Test method minus(a, b)""" self.assertEqual(1, minus(3, 2)) def test_multi(self): """Test method multi(a, b)""" self.assertEqual(6, multi(2, 3)) @unittest.skip("I don't want to run this case.") def test_divide(self): """Test method divide(a, b)""" self.assertEqual(2, divide(6, 3)) self.assertEqual(3, divide(5, 2)) if __name__ == '__main__': unittest.main()