Frage

I am working on a Python module that suppose to checkout some code from SVN and build it. After much refactoring of some legacy code, I got a fairly decent coverage of the code, however, I have a gaping hole in the code that uses pysvn.

Admittedly the concept of Mock object is new to me, but after reading some of the documentation of MiniMock and pymox (both are available in my environment), I came to the conclusion that I will need to capture some pysvn output and have it returned in my test code.

But here I find myself (pardon the pun) in a pickle. The objects returned from the pysvn.Client() commands do not behave nicely when I try to pickle them, or even to compare them.

Any suggestion of how to serialize or otherwise mock pysvn or some other non-pythonic behaving objects?

Naturally, I am willing to accept that I am approaching this problem from the wrong direction, or that I am simply an idiot. In that case any advice will be helpful.

Additional information 0:

Some pysvn object can be reduced to a dict by accessing their data property, and can be reproduced by passing this dict into the appropriate __init__()

For example:

>>> 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'>

However inside this object there might be some unpicklable objects:

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

Additional Information 1:

As for @H. Dunlop request, here is a (simplified) snippet of my code, It allow to get a list out of SVN, and let the user choose an item from that list:

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()
War es hilfreich?

Lösung

In this answer I used minimock, I'm not actually that familiar with it and would suggest using http://www.voidspace.org.uk/python/mock/ instead. This code would end up a bit cleaner . But you specified minimock or pymox so here goes:

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()

If you wanted to test more of the underlying dictionary returned by pysvn then you can just modify the list of tuples with dictionaries inside of it that you make it return. You could even write a little bit of code that just dumped out the dictionaries from the pysvn objects .

Andere Tipps

Have you considered the use of: pickle instead cPicles? "cPickle module the callables Pickler() and Unpickler() are functions, not classes. This means that you cannot use them to derive custom pickling and unpickling subclasses."

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top