utils.py 的 Django 单元测试中模拟失败
Mocking fails in Django unittest of utils.py
我正在尝试为名为 search_ldap()
的函数编写单元测试,该函数在给定特定用户名的情况下搜索 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
的服务器和连接 类?
要模拟 class,您应该为它提供所需方法的假实现。例如:
class FakeServer:
def call():
pass
class LdapTest(TestCase):
@mock.patch('ldap3.Server', FakeServer)
def test_search_ldap(self):
<do you checks here>
对于 patch()
,重要的是在查找它们的名称空间中修补对象。这在文档的 Where to patch 部分进行了解释。 doing
有根本的区别
from ldap3 import Server
server = Server()
和
import ldap3
server = ldap3.Server()
第一种情况(也是原题中的情况),名称"Server"属于当前模块。在第二种情况下,名称 "Server" 属于定义它的 ldap3 模块。以下 Django 单元测试修补了正确的 "Server" 和 "Connection" 名称,并且应该按预期工作:
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)
我正在尝试为名为 search_ldap()
的函数编写单元测试,该函数在给定特定用户名的情况下搜索 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
的服务器和连接 类?
要模拟 class,您应该为它提供所需方法的假实现。例如:
class FakeServer:
def call():
pass
class LdapTest(TestCase):
@mock.patch('ldap3.Server', FakeServer)
def test_search_ldap(self):
<do you checks here>
对于 patch()
,重要的是在查找它们的名称空间中修补对象。这在文档的 Where to patch 部分进行了解释。 doing
from ldap3 import Server
server = Server()
和
import ldap3
server = ldap3.Server()
第一种情况(也是原题中的情况),名称"Server"属于当前模块。在第二种情况下,名称 "Server" 属于定义它的 ldap3 模块。以下 Django 单元测试修补了正确的 "Server" 和 "Connection" 名称,并且应该按预期工作:
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)