【问题标题】:Mocking fails in Django unittest of utils.py在 utils.py 的 Django 单元测试中模拟失败
【发布时间】:2016-04-12 10:17:19
【问题描述】:

我正在尝试为名为@9​​87654322@ 的函数编写单元测试,该函数搜索给定特定用户名的LDAP 服务器。这是utils.py 中的函数定义(注意:我使用的是Python 3):

from ldap3 import Server, Connection
def search_ldap(username):
    result = ()
    baseDN = "o=Universiteit van Tilburg,c=NL"
    searchFilter = '(uid={})'.format(username)
    attributes = ['givenName', 'cn', 'employeeNumber', 'mail']

    try:
        server = Server('ldap.example.com', use_ssl=True)
        conn = Connection(server, auto_bind=True)
        conn.search(baseDN, searchFilter, attributes=attributes)
        for a in attributes:
            result += (conn.response[0]['attributes'][a][0], )
    except Exception:
        raise LDAPError('Error in LDAP query')

    return result

当然我不想在测试期间实际连接到ldap.example.com,所以我决定在我的单元测试中使用Python 的mock object library 来模拟Server()Connection() 类。下面是测试代码:

from unittest import mock
from django.test import TestCase
class LdapTest(TestCase):
    @mock.patch('ldap3.Server')
    @mock.patch('ldap3.Connection')
    def test_search_ldap(self, mockConnection, mockServer):
        from .utils import search_ldap
        search_ldap('username')
        self.assertTrue(mockServer.called)
        self.assertTrue(mockConnection.called)

此测试只是断言模拟的 Server 和 Connection 对象已实例化。但是,他们没有,因为当我使用 ./manage.py test 运行测试时,我收到以下错误:

Creating test database for alias 'default'...
F.
======================================================================
FAIL: test_search_ldap (uvt_user.tests.LdapTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/lib/python3.4/unittest/mock.py", line 1142, in patched
    return func(*args, **keywargs)
  File "/home/jj/projects/autodidact/uvt_user/tests.py", line 28, in test_search_ldap
    self.assertTrue(mockServer.called)
AssertionError: False is not true

----------------------------------------------------------------------
Ran 2 tests in 0.030s

FAILED (failures=1)
Destroying test database for alias 'default'...

为什么我的测试失败了?如何成功模拟ldap3 的服务器和连接类?

【问题讨论】:

    标签: python django unit-testing python-3.x mocking


    【解决方案1】:

    要模拟类,您应该为其提供所需方法的假实现。例如:

    class FakeServer:
        def call():
            pass
    
    class LdapTest(TestCase):
        @mock.patch('ldap3.Server', FakeServer)
        def test_search_ldap(self):
            <do you checks here>
    

    【讨论】:

    • 好吧,根据the documentation,你也可以省略一个虚假的实现并用一个参数调用patch()。尽管如此,我尝试了您的解决方案,但 utils.py 仍然导入原始的 ldap3 模块而不是模拟的模块。
    【解决方案2】:

    对于patch(),在查找对象的命名空间中修补对象非常重要。这在文档的Where to patch 部分进行了解释。做和做是有根本区别的

    from ldap3 import Server
    server = Server()
    

    import ldap3
    server = ldap3.Server()
    

    在第一种情况下(也是原始问题中的情况),名称“服务器”属于当前模块。在第二种情况下,名称“Server”属于定义它的 ldap3 模块。以下 Django 单元测试修补了正确的“服务器”和“连接”名称,并且应该按预期工作:

    from unittest import mock
    from django.test import TestCase
    class LdapTest(TestCase):
        @mock.patch('appname.utils.Server')
        @mock.patch('appname.utils.Connection')
        def test_search_ldap(self, mockConnection, mockServer):
            from .utils import search_ldap
            search_ldap('username')
            self.assertTrue(mockServer.called)
            self.assertTrue(mockConnection.called)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-11-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多