Как издеваться над писвн

Я работаю над модулем Python, который предполагает извлечь некоторый код из SVN и собрать его. После большого рефакторинга некоторого унаследованного кода я получил достаточно приличный охват кода, однако у меня есть зияющая дыра в коде, который использует pysvn.

По общему признанию, концепция объекта Mock является новой для меня, но после прочтения некоторой документации по MiniMock и pymox (обе доступны в моей среде), я пришел к выводу, что мне нужно будет захватить некоторый вывод pysvn и вернуть его в мой тестовый код.

Но здесь я оказываюсь (простите за каламбур) в рассоле. Объекты, возвращаемые командами pysvn.Client(), не ведут себя хорошо, когда я пытаюсь их выделить или даже сравнить.

Любое предложение о том, как сериализовать или иным образом издеваться над pysvn или какими-то другими объектами непитонического поведения?

Естественно, я готов признать, что подхожу к этой проблеме с неправильной стороны, или что я просто идиот. В этом случае любой совет будет полезен.

Дополнительная информация 0:

Немного pysvn объект может быть уменьшен до dict путем доступа к их data свойство, и может быть воспроизведено путем передачи этого dict в соответствующий __init__()

Например:

>>> svn=pysvn.Client()
>>> svn.list('http://svn/svn/')[0][0]
<PysvnList u'http://svn/svn'>
>>> d=svn.list('http://svn/svn/')[0][0].data
>>> pysvn.PysvnList(d)
<PysvnList u'http://svn/svn'>

Однако внутри этого объекта могут быть некоторые непопулярные объекты:

>>> cPickle.dumps(d)
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
cPickle.UnpickleableError: Cannot pickle <type 'node_kind'> objects

Дополнительная информация 1:

Что касается aychedee. Запрос aychedee, вот (упрощенный) фрагмент моего кода. Он позволяет получить список из SVN и позволить пользователю выбрать элемент из этого списка:

class Menu(object):
    """a well covered class"""
    # ...

class VersionControl(object):
    """A poorly covered class"""

    def __init__(self):
        self.svn = pysvn.Client()

    # ...

    def list(self, url):
        """svn ls $url"""
        return [os.path.basename(x['path']) for (x,_) in self.svn.list(url)[1:]]

    def choose(self, choice, url):
        """Displays a menu from svn list, and get's the users choice form it.

        Returns the svn item (path).
        """
        menu = Menu(prompt="Please choose %s from list:\n" % choice,
                    items=self.list(url),
                    muliple_choice=False)
        menu.present()
        return menu.chosen()

2 ответа

Решение

В этом ответе я использовал minimock, на самом деле я не очень знаком с ним и рекомендую использовать http://www.voidspace.org.uk/python/mock/. Этот код будет немного чище. Но вы указали minimock или pymox, так что здесь идет:

from minimock import TraceTracker, Mock, mock
import unittest

import pysvn

from code_under_test import VersionControl


class TestVersionControl(unittest.TestCase):


    def test_init(self):

        mock_svn = Mock(name='svn_client')
        mock('pysvn.Client', returns=mock_svn)

        vc = VersionControl()

        self.assertEqual(vc.svn, mock_svn)


    def test_list_calls_svn_list_and_returns_urls(self):

        tracker = TraceTracker()
        test_url = 'a test_url'
        mock_data = [
            ({'path': 'first result excluded'}, None),
            ({'path': 'url2'}, None),
            ({'path': 'url3', 'info': 'not in result'}, None),
            ({'path': 'url4'}, None),
        ]

        vc = VersionControl()
        mock('vc.svn.list', returns=mock_data, tracker=tracker)

        response = vc.list(test_url)
        self.assertEqual(['url2', 'url3', 'url4'], response)
        self.assertTrue("Called vc.svn.list('a test_url')" in tracker.dump())


if __name__ == '__main__':
    unittest.main()

Если вы хотите протестировать больше базового словаря, возвращаемого pysvn, вы можете просто изменить список кортежей со словарями внутри него, чтобы он возвращал его. Вы могли бы даже написать немного кода, который просто выводил словари из объектов pysvn.

Рассматривали ли вы использование: pickle вместо cPicles? "В модуле cPickle вызываемые функции Pickler() и Unpickler() являются функциями, а не классами. Это означает, что вы не можете использовать их для получения пользовательских подклассов выбора и удаления параметров".

Другие вопросы по тегам