[TIP] Should I always provide a return value when writing my test using mock library?

John Wong gokoproject at gmail.com
Thu Apr 12 13:34:17 PDT 2012


Dear Eric & Carl

Thanks to both of you. Yes. Eric, your solution calls the mock version (I
modified the assert a bit because, I think the the expected output is
`args=['123']` rather than `args='123`).

The snippet of the old mock and new mock is found here:
http://dpaste.org/vPswS/

Observations:
1. test cases return `codebundle.tests`
2. inside render_reverse, it returns `codebundles.lib` (guess this means it
is returning the local binding of `reverse`)

Yes. I am aware of the nice feature in 1.4, but I have to first verify them
in my old Django (I am running 1.2.1.... omg)


> The assertion of the result might be pointless, but it feels like it
confirms what the code under test should produce.
> Also, I realize I dropped the "dummy_views" from the argument simply b/c
it seems superfluous in my example.
> Obviously, if it necessary, then it is necessary and should be in the
test… right?

Not at all. Like Carl said, it was pointless and bad to supply mock objects
to the arguments in many cases. In this particular case, they are just
`string type`. A dummy `foo` string will do it. I think these two
assertions are good (although many people follow the one assertion per test
rule). So if you want to assert that it did call with the args we passed
in, for the sake of "getting the right info of what goes wrong", we can
write a test for each assertion. Actually, I am new to this mailing list so
I created a duplicate. Carl explains this really well in his first reply:
http://lists.idyll.org/pipermail/testing-in-python/2012-April/004913.html


--
John

On Thu, Apr 12, 2012 at 3:46 PM, Eric Larson <eric at ionrock.org> wrote:

> On Thursday, April 12, 2012 at 2:18 PM, John Wong wrote:
> > First, I hope I am not making duplicate (my first time using this kind
> of mailing list...)
> >
> > > The first thing is to be clear in your mind which code you are
> intending
> > > to test. In this case, it sounds like you want to test your
> > > "render_reverse" function, but without exercising Django's "reverse"
> > > (which makes it a unit test). Mocking "reverse" is a reasonable way to
> > > go about this.
> >
> >
> > Yes. Exactly. I want to perform a unittest on this function, which calls
> django's reverse (for whatever reason why I am doing this...)
> >
> > Here is the actual function from lib.py (there is no class involved, all
> functions in lib.py)
> >
> > from django.core.urlresolvers import reverse
> > def render_reverse(f, kwargs):
> > """
> > kwargs is a dictionary, usually of the form {'args': [cbid]}
> > """
> > return reverse(f, **kwargs)
> >
> > Because the name lookup is `reverse`, so I should patch
> `myproject.myapps.mylibrary.reverse` as opposed to
> `django.core.urlresolvers.reverse`
> >
> > I did the first method. I want to assert that `render_reverse` generates
> whatever `reverse` generates (by calling `reverse` directly). That's the
> goal. So I have the following test code:
> >
> > from lib import render_reverse, print_ls
> >
> > class LibTest(unittest.TestCase):
> >
> > def test_render_reverse_is_correct(self):
> > with patch('myproject.myapps.mylibrary.reverse') as mock_reverse:
> > from lib import render_reverse
> > mock_f = MagicMock(name='f', return_value='dummy_views')
> > mock_kwargs = MagicMock(name='kwargs',return_value={'args':['123']})
> > mock_reverse.return_value = '/natrium/cb/details/123'
> > response = render_reverse(mock_f(), mock_kwargs())
> > print mock_reverse.mock_calls # prints []
> > print mock_reverse.mock_calls # prints []
> > self.assertTrue('/natrium/cb/details/' in response)
> >
>
> I might consider rewriting the test like this:
>
> import lib
> import mock
>
> @mock.patch.object(lib, 'reverse')
> def test_render_reverse(mock_reverse):
>    result = lib.render_reverse('foo', {'args': ['123']})
>    mock_reverse.assert_called_with('foo', args='123')
>    assert result == mock_reverse('foo', args='123')
>
> The assertion of the result might be pointless, but it feels like it
> confirms what the code under test should produce. Also, I realize I dropped
> the "dummy_views" from the argument simply b/c it seems superfluous in my
> example. Obviously, if it necessary, then it is necessary and should be in
> the test… right?
>
> If others have comments on my refactoring please let me know. I'm new to
> the mock library and have been in the process of updating a rather old and
> unorganized test suite, so tips, tricks and best practices are all
> appreciated.
>
> Thanks!
>
> Eric
> >
> > Observations:
> > 1. mock_reverse was never because `mock_calls` returns []. I've asserted
> with `called` method, and it returns False.
> > 2. using render_reverse like this, the name `dummy_views` must exists -
> it must be a view function that actually exists in my Django project.
> Otherwise, it will return an error.
> > 3. using render_reverse like this, the speed takes 0.2 - 0.3 seconds, as
> opposed to 0.06 s when I used `mock_reverse`.
> >
> > Is there anything wrong the code? I understand that `mock_f` and
> `mock_kwargs` should be just simple input, rather than mock objects.
> >
> > Thanks, Carl.
> > _______________________________________________
> > testing-in-python mailing list
> > testing-in-python at lists.idyll.org (mailto:
> testing-in-python at lists.idyll.org)
> > http://lists.idyll.org/listinfo/testing-in-python
>
>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.idyll.org/pipermail/testing-in-python/attachments/20120412/4672915c/attachment-0001.htm>


More information about the testing-in-python mailing list