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()
执行结果:
test_add (test_mathfunc.TestMathFunc) Test method add(a, b) ... ok test_divide (test_mathfunc.TestMathFunc) Test method divide(a, b) ... skipped "I don't want to run this case." test_minus (test_mathfunc.TestMathFunc) Test method minus(a, b) ... ok test_multi (test_mathfunc.TestMathFunc) Test method multi(a, b) ... ok ---------------------------------------------------------------------- Ran 4 tests in 0.000s OK (skipped=1)
可以看到总的test数量还是4个,但divide()方法被skip了。
skip装饰器一共有三个:
- unittest.skip(reason) :无条件跳过
- unittest.skipIf(condition, reason) :f当condition为True时跳过
- unittest.skipUnless(condition, reason) :当condition为False时跳过。
2)TestCase.skipTest()方法
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.skipTest('Do not run this.') # 即TestCase.skipTest() self.assertEqual(2, divide(6, 3)) self.assertEqual(3, divide(5, 2)) if __name__ == '__main__': unittest.main()
执行结果:
test_add (test_mathfunc.TestMathFunc) Test method add(a, b) ... ok test_divide (test_mathfunc.TestMathFunc) Test method divide(a, b) ... skipped 'Do not run this.' test_minus (test_mathfunc.TestMathFunc) Test method minus(a, b) ... ok test_multi (test_mathfunc.TestMathFunc) Test method multi(a, b) ... ok ---------------------------------------------------------------------- Ran 4 tests in 0.000s OK (skipped=1)
用HTMLTestRunner输出漂亮的HTML报告
HTMLTestRunner是一个第三方的unittest HTML报告库,HTMLTestRunner.py文件的创建参考下面内容
demo:
import unittest from test_mathfunc import TestMathFunc from HTMLTestRunner import HTMLTestRunner if __name__ == '__main__': suite = unittest.TestSuite() suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestMathFunc)) with open(r'D:\HTMLReport.html', 'wb') as f: runner = HTMLTestRunner(stream=f, title='MathFunc Test Report', description='generated by HTMLTestRunner.', verbosity=2 ) runner.run(suite)
执行结果,控制台上可以看到:
ok test_add (test_mathfunc.TestMathFunc)
F test_divide (test_mathfunc.TestMathFunc)
ok test_minus (test_mathfunc.TestMathFunc)
ok test_multi (test_mathfunc.TestMathFunc)
Time Elapsed: 0:00:00.002000
并且在D盘中生成了HTMLReport.html,打开如下:
HTMLTestRunner介绍
HTMLTestRunner url:http://tungwaiyip.info/software/HTMLTestRunner_0_8_2/HTMLTestRunner.py
1)进入链接,复制代码,重新生成一个HTMLTestRunner.py文件,将复制的代码copy进去
2)将HTMLTestRunner.py文件放到python安装目录的Lib目录下
3)项目需要用到时,将HTMLTestRunner.py文件导入到项目中使用即可
""" A TestRunner for use with the Python unit testing framework. It generates a HTML report to show the result at a glance. The simplest way to use this is to invoke its main method. E.g. import unittest import HTMLTestRunner ... define your tests ... if __name__ == '__main__': HTMLTestRunner.main() For more customization options, instantiates a HTMLTestRunner object. HTMLTestRunner is a counterpart to unittest's TextTestRunner. E.g. # output to a file fp = file('my_report.html', 'wb') runner = HTMLTestRunner.HTMLTestRunner( stream=fp, title='My unit test', description='This demonstrates the report output by HTMLTestRunner.' ) # Use an external stylesheet. # See the Template_mixin class for more customizable options runner.STYLESHEET_TMPL = '' # run the test runner.run(my_test_suite) ------------------------------------------------------------------------ Copyright (c) 2004-2007, Wai Yip Tung All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name Wai Yip Tung nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. """ # URL: http://tungwaiyip.info/software/HTMLTestRunner.html __author__ = "Wai Yip Tung" __version__ = "0.8.2" """ Change History Version 0.8.2 * Show output inline instead of popup window (Viorel Lupu). Version in 0.8.1 * Validated XHTML (Wolfgang Borgert). * Added description of test classes and test cases. Version in 0.8.0 * Define Template_mixin class for customization. * Workaround a IE 6 bug that it does not treat %(heading)s %(report)s %(ending)s