pythonmockingdecoratorpatchnose2

Use mock.patch decorators with nose2 Such DSL


Nose2 has this awesome Such DSL that works similar to RSpec. I used to use unittests directly and decorated the function with something like mock.patch. I am wondering how the should decorated functions differ from regular unittest functions, and how can I use other decorators as for unittest functions.

I can get it to work like this, but it seems like losing the ability of passing in the unittest instance in the arguments. Any advise will be super appreciated. Thanks!

@it.should('do something')
@mock.patch('my.package.lib.b')                                                                
@mock.patch('my.package.lib.a')                                                                   
def test(a, b):
    pass

Solution

  • So we know that decorator order matters and none of these work:

    @it.should('do something')
    @mock.patch('datetime.date')
    @mock.patch('datetime.time')
    def test_1(date, time, case):
        pass
    
    @mock.patch('datetime.time')
    @mock.patch('datetime.date')
    @it.should('do something')
    def test_2(case, date, time):
        pass
    

    because of the way patch and should are implemented. Both libraries make some assumptions about what the resulting decorated function will be so it's not possible to directly pass a result of decoration from one to the other.

    But we can make a fix for that from the outside using an "adapter" decorator:

    import mock
    import nose2.tools
    
    def fix_case(f):
        def test(case):
            f(case=case)
        return test
    
    with nose2.tools.such.A('system') as it:
    
        @it.should('do something')
        @fix_case
        @mock.patch('datetime.time')
        @mock.patch('datetime.date')
        def test_3(date, time, case=None):
            print(date, time, case)
    
    it.createTests(globals())
    

    Now this works and results in:

    $ nose2 -v
    test 0000: should do something (tests.test_nose2_such.A system) ...
    (<MagicMock name='date' id='4334752592'>, <MagicMock name='time' id='4334762000'>,
    <tests.test_nose2_such.A system testMethod=test 0000: should do something>)
    ok
    
    ----------------------------------------------------------------------
    Ran 1 test in 0.001s
    
    OK
    

    This is rather quick and dirty but get's the job done. I'll see if I can improve upon this and make it nicer.