Уведомления

Группа в Telegram: @pythonsu

#1 Дек. 23, 2015 20:07:03

Master_Sergius
Зарегистрирован: 2013-09-12
Сообщения: 271
Репутация: +  7  -
Профиль   Отправить e-mail  

Mock и импортируемые модули/функции

Схематическое изложение (ибо всё секретно )
имеется модуль, который нужно протестировать - “master_module.py”:

# different imports, path patches, etc...
...
from clients import WebAPIClient
from utils.conf import config
 
class WebClient(object):
 
    def __init__(self):                                                         
           conf = config.get_config('web')                                        
           self.__client = WebAPIClient(host=conf['master_service.host'],\
                                                         user=conf['master_service.user'], \
                                                         password=conf['master_service.password'])
   ....
   # different methods
   ....

Суть в том, что не получается подсунуть “замокать” config.get_config(), чтобы он вернул нужный словарь. К примеру, если в юниттесте я сделаю так:

sys.modules['utils.conf'] = Mock()
 
from master_module import WebClient
 
config = Mock()
config.get_config = Mock(return_value={'master_service.host':'mock_host', 'master_service.user':'mock_user', 'corpus_api.password':'mock_pass'})
print config.get_config()

то он напечатает нужный словарь, но когда вызываю:

client = WebClient()

то этот замоканный config не передается, а передается лишь - sys.modules = Mock(), в итоге получаю:

Traceback .... bla-bla .... in __init__
    host=conf['master_service.host'], \
TypeError: 'Mock' object is unsubscriptable

Как решить данную проблему?


Сумел пропатчить вот таким способом:

import clients
globals()['clients'].config = config # assign mocked config

где config - это уже тот мой замоканный

Возможно, есть более элегантное решение? Или вообще другой подход к такому тестированию?



———————————————————————————
Мой блог о семействе *nix: http://nixtravelling.blogspot.com/

Отредактировано Master_Sergius (Дек. 23, 2015 21:01:52)

Офлайн

#2 Дек. 24, 2015 02:54:38

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 9894
Репутация: +  854  -
Профиль   Отправить e-mail  

Mock и импортируемые модули/функции

Master_Sergius
Возможно, есть более элегантное решение?
Надо патчить прямо в том модуле.
from utils.conf import config



Офлайн

#3 Дек. 24, 2015 10:59:59

Master_Sergius
Зарегистрирован: 2013-09-12
Сообщения: 271
Репутация: +  7  -
Профиль   Отправить e-mail  

Mock и импортируемые модули/функции

py.user.next
Надо патчить прямо в том модуле.
from utils.conf import config

В смысле? Дописывать что-то в другой модуль? Не думаю, что это верное решение. Юниттесты никоим образом не должны влиять на модули.



———————————————————————————
Мой блог о семействе *nix: http://nixtravelling.blogspot.com/

Офлайн

#4 Дек. 24, 2015 11:44:37

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 9894
Репутация: +  854  -
Профиль   Отправить e-mail  

Mock и импортируемые модули/функции

Master_Sergius
В смысле? Дописывать что-то в другой модуль?
Не дописывать, а использовать patch().

>>> from unittest.mock import patch
>>> 
>>> p = patch('os.path.join')
>>> p.start()
<MagicMock name='join' id='3073445324'>
>>> 
>>> import os
>>> 
>>> os.path.join('x')
<MagicMock name='join()' id='3073462732'>
>>> 
>>> p.stop()
>>>

Пример
t.py
#!/usr/bin/env python3
 
import os
 
def main():
    print('hello')
    print(os.path.join('x', 'y'))
 
if __name__ == '__main__':
    main()

u.py
#!/usr/bin/env python3
 
from unittest.mock import patch
import t
 
p = patch('os.path.join')
p.start()
 
t.main()
 
p.stop()

Вывод
[guest@localhost py]$ ./t.py 
hello
x/y
[guest@localhost py]$ ./u.py
hello
<MagicMock name='join()' id='3073278892'>
[guest@localhost py]$



Отредактировано py.user.next (Дек. 24, 2015 11:45:28)

Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version