python接口测试框架实战与自动化进阶


 

 一、fiddler在工作中的运用

 1、如何抓接口

  抓紧手机端接口

  ①、在电脑终端输入:ipconfig ,找到电脑ip

  ②、打开手机,连接WiFi,进入WiFi详情,改用手动代理,将ip设置为电脑端的ip,端口默认(8888)

 python接口测试框架实战与自动化进阶(一)

  ③、打开fiddler,找到并打开Fiddler Options ,选择Connections栏,做如下改动:

  python接口测试框架实战与自动化进阶(一)

这样就可以尝试抓取接口了。

注: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 
这就是一个简单的测试,有几点需要说明的:

  1. 在第一行给出了每一个用例执行的结果的标识,成功是 .,失败是 F,出错是 E,跳过是 S。从上面也可以看出,测试的执行跟方法的顺序没有关系,test_divide写在了第4个,但是却是第2个执行的。
  2. 每个测试方法均以 test 开头,否则是不被unittest识别的。
  3. 在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()
View Code

相关文章: