2016-04-12 3 views
0

Я пытаюсь написать unittest для функции с именем search_ldap(), которая ищет сервер LDAP с заданным конкретным именем пользователя. Вот определение функции в utils.py (примечание: Я использую Python 3):Mocking не работает в Django unittest из utils.py

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() в моих unittests. Ниже приведено тестовое код:

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) 

Этот тест просто подтверждает, что объекты, издевавшиеся над Сервером и соединением, создаются. Однако, Тэй нет, потому что, когда я запускаю тесты с ./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?

ответ

0

Чтобы издеваться над классом, вы должны предоставить его поддельную реализацию с помощью необходимых методов. Например:

class FakeServer: 
    def call(): 
     pass 

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

Ну, согласно [документации] (https://docs.python.org/dev/library/ unittest.mock.html # quick-guide), вы также можете оставить фальшивую реализацию и вызвать 'patch()' с помощью одного аргумента. Тем не менее, я попробовал ваше решение, и utils.py по-прежнему импортирует оригинальный модуль 'ldap3', а не издевается над ним. – hedgie

0

С patch(), важно, чтобы вы залатать объекты в пространстве имен, где они смотрели вверх. Это объясняется в разделе документации Where to patch. Существует принципиальная разница между выполнением

from ldap3 import Server 
server = Server() 

и

import ldap3 
server = ldap3.Server() 

В первом случае (также случай в оригинальном вопросе), название «Сервер» относится к текущему модулю. Во втором случае имя «Сервер» принадлежит модулю ldap3, где он определен. Следующий Джанго UnitTest заплаты правильный «сервер» и имена «Подключение» и должны работать по назначению:

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) 
Смежные вопросы