天天看點

Python自動化測試-單元測試架構unittest

一.概念

unittest中最核心的四個概念是:test case, test suite, test runner, test fixture。

test case,:一個TestCase的執行個體就是一個測試用例

test suite:而多個測試用例集合在一起,就是TestSuite,而且TestSuite也可以嵌套TestSuite

testLoader是将TestCase加載到TestSuite裡,用loadTestsFrom__()等幾個方法,找到testcase建立它們的執行個體,然後add到TestSuite中,再傳回一個TestSuite執行個體。

test runner:TextTestRunner是來執行測試用例的,其中的run(test)會執行TestSuite/TestCase中的run(result)方法。 測試的結果會儲存到TextTestResult執行個體中,包括運作了多少測試用例,成功了多少,失敗了多少等資訊。

test fixture:而對一個測試用例環境的搭建和銷毀,是一個fixture。

流程描述:寫好TestCase,然後由TestLoader加載TestCase到TestSuite,然後由TextTestRunner來運作TestSuite,運作的結果儲存在TextTestResult中,我們通過指令行或者unittest.main()執行時,main會調用TextTestRunner中的run來執行,或者我們可以直接通過TextTestRunner來執行用例。這裡加個說明,在Runner執行時,預設将執行結果輸出到控制台,我們可以設定其輸出到檔案,在檔案中檢視結果(通過HTMLTestRunner可以将結果輸出到HTML中,生成漂亮的報告,它跟TextTestRunner是一樣的,從名字就能看出來,這個我們後面再說)

二.執行個體運作

# -*- coding: utf-8 -*-

import unittest
from mathfunc import *


class TestMathFunc(unittest.TestCase):
    """Test mathfuc.py"""

    def setUp(self):
        print "do something before test.Prepare environment."

    def tearDown(self):
        print "do something after test.Clean up."

    def test_add(self):
        """Test method add(a, b)"""
        print "add"
        self.assertEqual(3, add(1, 2))
        self.assertNotEqual(3, add(2, 2))

    def test_minus(self):
        """Test method minus(a, b)"""
        print "minus"
        self.assertEqual(1, minus(3, 2))

    def test_multi(self):
        """Test method multi(a, b)"""
        print "multi"
        self.assertEqual(6, multi(2, 3))

    def test_divide(self):
        """Test method divide(a, b)"""
        print "divide"
        self.assertEqual(2, divide(6, 3))
        self.assertEqual(2.5, divide(5, 2))
           

test fixture之setUp() tearDown()

上面整個測試基本跑了下來,但可能會遇到點特殊的情況:如果我的測試需要在每次執行之前準備環境,或者在每次執行完之後需要進行一些清理怎麼辦?比如執行前需要連接配接資料庫,執行完成之後需要還原資料、斷開連接配接。總不能每個測試方法中都添加準備環境、清理環境的代碼吧。

我們添加了 

setUp()

 和 

tearDown()

 兩個方法(其實是重寫了TestCase的這兩個方法),這兩個方法在每個測試方法執行前以及執行後執行一次,setUp用來為測試準備環境,tearDown用來清理環境,已備之後的測試。

三.将結果輸出到檔案中

用例組織好了,但結果隻能輸出到控制台,這樣沒有辦法檢視之前的執行記錄,我們想将結果輸出到檔案。很簡單,看示例:

修改test_suite.py:

# -*- coding: utf-8 -*-

import unittest
from test_mathfunc import TestMathFunc

if __name__ == '__main__':
    suite = unittest.TestSuite()
    suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestMathFunc))

    with open('UnittestTextReport.txt', 'a') as f:
        runner = unittest.TextTestRunner(stream=f, verbosity=2)
        runner.run(suite)
           

 四.輸出美觀的測試報告----HTMLTestRunner

HTMLTestRunner是一個第三方的unittest HTML報告庫,首先我們下載下傳HTMLTestRunner.py,并放到目前目錄下,或者你的’C:\Python27\Lib’下,就可以導入運作了。

test_suite.py

# -*- coding: utf-8 -*-

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('HTMLReport.html', 'w') 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.001000
           

并且輸出了HTML測試報告,

HTMLReport.html

五.跳過某個case-skip裝飾器

skip裝飾器一共有三個 

unittest.skip(reason)

unittest.skipIf(condition, reason)

unittest.skipUnless(condition, reason)

,skip無條件跳過,skipIf當condition為True時跳過,skipUnless當condition為False時跳過。

  1. skip裝飾器
...

class TestMathFunc(unittest.TestCase):
    """Test mathfuc.py"""

    ...

    @unittest.skip("I don't want to run this case.")
    def test_divide(self):
        """Test method divide(a, b)"""
        print "divide"
        self.assertEqual(2, divide(6, 3))
        self.assertEqual(2.5, divide(5, 2))
           

執行:

...
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了。

2.TestCase.skipTest()方法

...

class TestMathFunc(unittest.TestCase):
    """Test mathfuc.py"""

    ...

    def test_divide(self):
        """Test method divide(a, b)"""
        self.skipTest('Do not run this.')
        print "divide"
        self.assertEqual(2, divide(6, 3))
        self.assertEqual(2.5, divide(5, 2))
           

輸出:

...
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.001s

OK (skipped=1)
           

效果跟上面的裝飾器一樣,跳過了divide方法。

六.總結

總結一下:

  1. unittest是Python自帶的單元測試架構,我們可以用其來作為我們自動化測試架構的用例組織執行架構。
  2. unittest的流程:寫好TestCase,然後由TestLoader加載TestCase到TestSuite,然後由TextTestRunner來運作TestSuite,運作的結果儲存在TextTestResult中,我們通過指令行或者unittest.main()執行時,main會調用TextTestRunner中的run來執行,或者我們可以直接通過TextTestRunner來執行用例。
  3. 一個class繼承unittest.TestCase即是一個TestCase,其中以 

    test

     開頭的方法在load時被加載為一個真正的TestCase。
  4. verbosity參數可以控制執行結果的輸出,  是簡單報告、

    1

     是一般報告、

    2

     是詳細報告。
  5. 可以通過addTest和addTests向suite中添加case或suite,可以用TestLoader的loadTestsFrom__()方法。
  6. 用 

    setUp()

    tearDown()

    setUpClass()

    以及 

    tearDownClass()

    可以在用例執行前布置環境,以及在用例執行後清理環境
  7. 我們可以通過skip,skipIf,skipUnless裝飾器跳過某個case,或者用TestCase.skipTest方法。
  8. 參數中加stream,可以将報告輸出到檔案:可以用TextTestRunner輸出txt報告,以及可以用HTMLTestRunner輸出html報告。

來自原文轉載位址:https://huilansame.github.io/huilansame.github.io/archivers/python-unittest

繼續閱讀