The Hacker's Guide To Python 單元測試

The Hacker's Guide To Python 單元測試

基本方式

python中提供了很是簡單的單元測試方式,利用nose包中的nosetests命令能夠實現簡單的批量測試。python

安裝nose網絡

sudo pip install nose

編輯測試文件app

# test_true.py
def test_true():
    assert True

def test_false():
    assert False

執行測試python2.7

# 命令, nosetests命令會加載全部以test_開頭的文件,並執行全部以test_開頭的函數
nosetests -v
# 輸出
test_true.test_true ... ok
test_true.test_false ... FAIL

======================================================================
FAIL: test_true.test_false
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/site-packages/nose/case.py", line 197, in runTest
    self.test(*self.arg)
  File "/xxxx/workspace/py/test/test_true.py", line 5, in test_false
    assert False
AssertionError

----------------------------------------------------------------------
Ran 2 tests in 0.007s

FAILED (failures=1

unittest是python提供了單元測試的標準庫。ide

# 爲了兼容python 2.6和2.7
try:
    import unittest2 as unittest
except ImportError:
    import unittest

class TestKey(unittest.TestCase):
    def test_keyh(self):
        a = ['a']
        b = ['a', 'b']
        self.assertEqual(a, b)

輸出以下,函數

test_keyh (test_true.TestKey) ... FAIL

======================================================================
FAIL: test_keyh (test_true.TestKey)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/y/workspace/py/test/test_true.py", line 8, in test_keyh
    self.assertEqual(a, b)
AssertionError: Lists differ: ['a'] != ['a', 'b']

Second list contains 1 additional elements.
First extra element 1:
b

- ['a']
+ ['a', 'b']

----------------------------------------------------------------------
Ran 1 test in 0.006s

FAILED (failures=1)

此外,unittest.skipIf能夠經過判斷條件來選擇是否進行測試,單元測試

class TestSkipped(unittest.TestCase):
    @unitttest.skip("Do not run this")
    def test_failt(self):
        self.fail("This should not be run")

    @unittest.skipIf(mylib is None, "mylib is not available")
    def test_mylib(self):
        self.assertEqual(1, 1)

此外,自定義setUptearDown函數能夠單元測試開始和結束時自動調用。測試

fixtures

fixtures模塊能夠用來臨時改變當前的測試環境。fetch

import fixtures
import os

class TestEnviron(fixtures.TestWithFixtures):
    def test_environ(self):
        fixture = self.useFixture(
                fixtures.EnvironmentVariable("FOOBAR", "42")) # 臨時增長一個環境變量FOOBAR
        self.assertEqual(os.environ.get("FOOBAR"), "42")

    def test_environ_no_fixture(self):
        self.assertEqual(os.environ.get("FOOBAR"), None) # 上面增長的環境變量的操做對於其餘函數無效

mock

mock模塊能夠用來進行模擬測試,其主要功能就是模擬一個函數,類或實例的行爲。ui

因爲網絡測試環境的特殊性,最經常使用的使用就是模擬網絡請求,具體例子以下,

# test_mock.py
import requests
import unittest
import mock

class WhereIsPythonError(Exception):
    pass

def is_python():
    try:
        r = requests.get("http://python.org")
    except IOError:
        pass
    else:
        if r.status_code == 200:
            return 'is python' in r.content
    raise WhereIsPythonError('something happened')

def get_fake_get(status_code, content):
    m = mock.Mock()
    m.status_code = status_code
    m.content = content
    def fake_get(url):
        return m
    return fake_get

def raise_get(url):
    raise IOError("unable to fetch url %s" % url)

class TestPython(unittest.TestCase):
    @mock.patch('requests.get', get_fake_get(
        200, 'is python, hello'
        ))
    def test_python_is(self):
        self.assertTrue(is_python())

    @mock.patch('requests.get', get_fake_get(
        200, 'is not python, hello'
        ))
    def test_python_is_not(self):
        self.assertFalse(is_python())

輸出以下,

# 命令
nosetests --tests=test_mock -v
# 結果
test_python_is (test_mock.TestPython) ... ok
test_python_is_not (test_mock.TestPython) ... ok

----------------------------------------------------------------------
Ran 2 tests in 0.001s

OK
相關文章
相關標籤/搜索