[TIP] Unit testing functions which call super

Marcin Tustin Marcin.Tustin at dealertrack.com
Wed Aug 13 14:39:21 PDT 2014


Thank you! This is the perfect thing for my usecase!

Two observations:
1. in the example code __name__ should be the full import name of the module in which Kid appears
2. this will not be suitable where there are multiple calls to super which call different super methods (i.e. it might call super(Kid, self).foo or super(Kid, self.bar)) and we want to distinguish between them (which is not my usecase).

Marcin

-----Original Message-----
From: Eric Larson [mailto:eric at ionrock.org] 
Sent: Wednesday, August 13, 2014 5:09 PM
To: Marcin Tustin
Cc: testing-in-python at lists.idyll.org
Subject: Re: [TIP] Unit testing functions which call super


Marcin Tustin writes:

> Hi All,
>
> I've come across a method which I needed to add a unit test for, which calls super, e.g.
>
> def foofunc(self):
>     x= do_some_stuff()
>     if x:
>         return x
>     return super(WhatevClass, self).foofunc()
>
> Now, I don't want to integration test the whole stack of super foofunc methods, just unit test that one, down to the super call.
>
> I've accomplished this with, in my test (excuse the 8 leading spaces):
>
> def setUp(self):
>         self.method_archive = {}
>         for klass in WhatevClass.__mro__[1:]:
>             # we use the class as its own sentinel
>             meth_or_klass = klass.__dict__.get('foofunc', klass)
>             if meth_or_klass != klass:
>                 self.method_archive[klass] = meth_or_klass
>                 del klass.foofunc
>         # now patch an arbitrary member of the mro to supply a dummy foofunc
>         self.sentinel_klass = next(iter(self.method_archive))
>         self.mock_sentinel = mock.MagicMock()
>         self.sentinel_klass.foofunc = self.mock_sentinel
>
>
> And corresponding unpatching in tearDown.
>
> Is there any other approach which is standard, or objectively better?
>

What about patching super?


    from mock import patch


    class Parent(object):

        def foo(self):
            print('foo from parent')


    class Kid(Parent):

        def foo(self):
            self.called_foo = True
            super(Kid, self).foo()


    class TestKid(object):

        @patch('%s.super' % __name__, create=True)
        def test_foo(self, super_func):
            kid = Kid()
            kid.foo()
            assert kid.called_foo
            assert super_func.called

That does the unpatching for you and hopefully reduces the potential of the patch leaking into other tests.

The downside is that this wouldn't cover the use case where an explicit parent method was called. Ie:

    def foo(self):
        ...
        return Parent.foo()

It sounds like if you are using multiple inheritance you're already avoiding this pattern.


HTH,

Eric


> Thanks,
> Marcin
>
> Marcin Tustin
> Senior Software Engineer
> ________________________________
>
>
> 1111 Marcus Avenue
> Lake Success, NY 11042
> dealertrack.com<https://www.dealertrack.com/>
> p 516.300.7072
>
> dealertrack technologies(tm)
>
> Confidentiality Notice: This e-mail and any attachments may contain 
> confidential, proprietary information of Dealertrack Technologies. It 
> is intended solely for the named recipient(s) listed above and should 
> be maintained in strictest confidence. If you are not the intended 
> recipient, you are hereby notified that any disclosure, copying, 
> distribution, or use of the information contained herein (including 
> any reliance thereon) is STRICTLY PROHIBITED. If you have received 
> this e-mail in error, please immediately notify the sender and delete 
> this information from your computer and destroy any related paper 
> copies. Unless otherwise expressly stated in the text of the e-mail, 
> the addition of a typed name or initials to this e-mail does not (i) 
> evidence an intent to sign the e-mail or (ii) constitute either (a) a 
> signature or (b) consent to use electronic records or signatures in 
> place of a writing or a handwritten signature
>
> _______________________________________________
> testing-in-python mailing list
> testing-in-python at lists.idyll.org
> http://lists.idyll.org/listinfo/testing-in-python

--
Sent with my mu4e



More information about the testing-in-python mailing list