• The Hacker's Guide To Python 单元测试


    The Hacker's Guide To Python 单元测试

    基本方式

    python中提供了非常简单的单元测试方式,利用nose包中的nosetests命令可以实现简单的批量测试。

    安装nose

    sudo pip install nose
    

    编辑测试文件

    # test_true.py
    def test_true():
        assert True
    
    def test_false():
        assert False
    

    执行测试

    # 命令, 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提供了单元测试的标准库。

    # 为了兼容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模块可以用来临时改变当前的测试环境。

    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模块可以用来进行模拟测试,其主要功能就是模拟一个函数,类或实例的行为。

    由于网络测试环境的特殊性,最常用的使用就是模拟网络请求,具体例子如下,

    # 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
    
  • 相关阅读:
    QR码与DM码的对比
    JBPM在Eclipse中运行时页面错误ProcessEngine cannot be resolved to a type
    C. A Mist of Florescence
    B. A Tide of Riverscape
    A. A Blend of Springtime
    A. Gennady the Dentist
    D. Lizard Era: Beginning
    E. Jzzhu and Apples
    D. Jzzhu and Cities
    C. Jzzhu and Chocolate
  • 原文地址:https://www.cnblogs.com/coder2012/p/5092190.html
Copyright © 2020-2023  润新知