Форум сайта python.su
У меня наблюдается категорическое непонимание технологии работы с моками, помогите, пожалуйста!
Имеется вот такой код:
from netrc import netrc
from transmissionrpc import Client as Transmission
def list_torrents(trans, _args):
"""List torrents."""
for num, torr in trans.list().iteritems():
fields = torr.fields
print num, fields['name'][:30], status(torr), torr.progress, torr.eta
def main():
nrc = netrc()
tr_login, _, tr_passwd = nrc.authenticators('localhost')
trans = Transmission(user=tr_login, password=tr_passwd, timeout=10)
list_torrents(trans, [])
Офлайн
#from netrc import netrc #from transmissionrpc import Client as Transmission def list_torrents(trans, _args): # ... def main(netrc, Transmission): # ...
Офлайн
Это о чем было? Можно поподробнее? Как я могу без них обойтись, если код, который я хочу тестировать использует transmissionrc и netrc?
PS: А, понял. Вы предлагаете гнуть код под тесты. Это порочный подход, по-моему.
Отредактировано Ed (Июнь 9, 2012 16:04:24)
Офлайн
Ed> Как я могу без них обойтись, если код, который я хочу тестировать использует transmissionrc и netrc?
Ну так мы же тестируем не netrc и transmissionrpc, зачем их приплетать. Обойтись без реальных реализаций можно передав тестируемому `main` свои dump'ы, с заранее известным поведением.
Ed> Вы предлагаете гнуть код под тесты. Это порочный подход, по-моему.
Отнюдь. Конечно, везде нужно знать меру и я ведь не предлагаю полностью в TDD уходить, хотя разработка через тестирование, например, позволят написать лучший API (мне позволяет :-) чем наколеночное проектирование.
А вот mock'и нужны далеко не всегда и скорее их использовании порочно. Я тоже какое-то время увлекся ими, но вовремя опомнился, теперь только для hook'ов использую при тестировании старого кода.
..bw
Офлайн
Я не хочу спорить, я хочу получить совет. Скажем так - условие у меня такое, что код я трогать не могу. Мне тесты для него нужно написать.
Но все равно, не удержусь:
Честно говоря за код такого вида:
from transmissionrc import client as Transmission
from netrc import netrc
def main(netrc, Transmission):
....
Отредактировано Ed (Июнь 9, 2012 16:32:14)
Офлайн
bwЯ выбрал mock, кроме всего прочего еще и потому что его автор - это автор unittest из стандартной библиотеки и mock туда же скоро попадет, если не попал уже. Я не люблю внешние зависимости, предпочитаю стандартные средства.
p.s. А вообще, мне больше Fudge нравится…
Офлайн
Пример, по-моему, неудачный. Там вроде нечего тестировать.
Может как-то так?
#!/usr/bin/env python # -*- coding: utf-8 -*- import mock from StringIO import StringIO netrc = mock.Mock() trans = mock.Mock() # сюда нужно будет вписать все торренты? # пока, просто моки desired_items = {i: mock.MagicMock() for i in range(10)} with mock.patch.dict('sys.modules', {'transmissionrpc': trans, 'netrc': netrc}): netrc.netrc.return_value.authenticators.return_value = ['user', '?', 'password'] trans.Client.return_value.list.return_value = desired_items with mock.patch('sys.stdout', new_callable=StringIO) as stdout: import some_lib some_lib.main() # assert 'desired output' in stdout.getvalue() print stdout.getvalue()
Офлайн
О, это уже интереснее, спасибо. А как сделать, чтобы работало
torr.fields['name'][:30]
Отредактировано Ed (Июнь 9, 2012 21:50:27)
Офлайн
EdТак работает, сохраненный вывод:
О, это уже интереснее, спасибо. А как сделать, чтобы работало? Просто MagicMock() думаю такого не сделает, его нужно научить как-то.torr.fields['name'][:30]
0 <MagicMock name='mock.fields.__getitem__().__getitem__()' id='26179088'> status? <MagicMock name='mock.progress' id='26473104'> <MagicMock name='mock.eta' id='26473264'>
1 <MagicMock name='mock.fields.__getitem__().__getitem__()' id='26578192'> status? <MagicMock name='mock.progress' id='26603408'> <MagicMock name='mock.eta' id='26624080'>
2 <MagicMock name='mock.fields.__getitem__().__getitem__()' id='26720816'> status? <MagicMock name='mock.progress' id='27098288'> <MagicMock name='mock.eta' id='27098448'>
3 <MagicMock name='mock.fields.__getitem__().__getitem__()' id='27215696'> status? <MagicMock name='mock.progress' id='27240912'> <MagicMock name='mock.eta' id='27241072'>
...
т.е. fields['name'] вызывает __getitem__ и возвращает magic_mock, также и magic_mock[:30] возвращает мок.
def status(x): return 'status?'
Отредактировано reclosedev (Июнь 9, 2012 22:18:08)
Офлайн
Нет, это я стормозил. Теперь такой вопрос. Тоже самое я делаю без всякого mock-а вот таким кодом:
class FakeTransmission(object):
def __init__(self, user, password, timeout=10):
pass
def list(self):
return {1: transmissionrpc.Torrent(self,
{'id': 1, 'name': 'My torrent', 'status': 0,
'sizeWhenDone': 100, 'leftUntilDone': 50,
'eta': 20})}
class FakeNetrc(object):
def authenticators(self, _host):
return 1, 2, 3
def test_ls():
mod.Transmission = FakeTransmission
mod.netrc = FakeNetrc
mod.sys.stdout = StringIO()
mod.main()
mod.sys.stdout.seek(0)
assert mod.sys.stdout.read() == "1 My torrent stopped 50.0 0:00:20\n"
Отредактировано Ed (Июнь 9, 2012 22:55:24)
Офлайн