[TIP] Return value of a read-only attribute only settable via 'return_value' kwarg

Michael Foord michael at voidspace.org.uk
Tue Apr 30 09:48:35 PDT 2013


On 30 Apr 2013, at 13:38, Balthazar Rouberol <rouberol.b at gmail.com> wrote:

> Hello all,
> 
> I wanted to mock an class read only property (which only does some I/O with mongoDB) by setting its return_value in an entire unittest.TestCase scope.
> 
> What I first tried was defining a patch in the classSetUp classmethod, then call its .start() method, and its .stop() method in tearDownClass.
> 
> @classmethod
> def setUpClass(cls):
>     # patch the Dataminer.blacklisted_domains so that it does not
>     # communicate with the database
>     cls.black_patch = mock.patch.object(
>        Dataminer,
>        'blacklisted_domains',
>        new_callable=mock.PropertyMock
>     )
>     cls.black_patch.return_value = ['some', 'manual', 'test', 'value']


Here cls.black_patch is the *patcher object* not the mock. It is responsible for creating the mock but is not itself the mock. So attaching a return_value to it has no effect. Calling patcher.start() creates and returns the mock object, so instead you should write:

   mock_thing = cls.black_patch.start()
   mock_thing.return_value = ['the', 'return', 'value']

All the best,

Michael

>     cls.black_patch.start()
> 
> @classmethod
> def tearDownClass(cls):
>     cls.black_patch.stop()
> 
> 
> However, when I called the Dataminer.blacklisted_domains property later in a test, it returned <MagicMock name='blacklisted_domains()' id='34773392'>, and not the value I defined.
> 
> What worked for me was passing the return_value as a kwarg to patch.object:
> 
> @classmethod
>     def setUpClass(cls):
>         # patch the Dataminer.blacklisted_domains so that it does not
>         # communicate with the database
>         cls.black_patch = mock.patch.object(
>             Dataminer,
>             'blacklisted_domains',
>             new_callable=mock.PropertyMock,
>             **{'return_value': ['some', 'manual', 'test', 'value']}
>         )
>         cls.black_patch.start()
> 
>     @classmethod
>     def tearDownClass(cls):
>         cls.black_patch.stop()
> 
> 
> With this method, the return value of the blacklisted_domains property of my Dataminer instance was what I defined in the classSetUp.
> 
> Could anyone walk me through the differences between these two methods, as it's not really clear to me why the first would fail when the second would work..
> 
> Thank you very much!
> --
> Balthazar Rouberol
> _______________________________________________
> testing-in-python mailing list
> testing-in-python at lists.idyll.org
> http://lists.idyll.org/listinfo/testing-in-python


--
http://www.voidspace.org.uk/


May you do good and not evil
May you find forgiveness for yourself and forgive others
May you share freely, never taking more than you give.
-- the sqlite blessing 
http://www.sqlite.org/different.html








More information about the testing-in-python mailing list