Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get per-testcase scoping for dependency injected objects in Python?

I'm using python-inject, python 2.6 (with unittest2).

We have classes to test that use injection, and test-cases which also use the same values. We currently use inject.appscope, to "singletonize" the values. Otherwise they're instantiated per user.

import inject

class A(object):
    '''shared data between many parts'''
    ...

class Foo(object):
    '''uses a to do stuff'''

    a = inject.attr('a', A)

    def bar(self):
        self.a.doStuff()

class TestFoo(TestCase):
    a = inject.attr('a', A)

    def setUp(self):
        self.foo = Foo()

    def testBar(self):
        self.foo.bar()
        self.assertTrue(self.a.stuffWasDone())
        self.assertFalse(self.a.stuffWasDoneTwice())

    def testBarTwice(self):
        self.foo.bar()
        self.foo.bar()
        self.assertTrue(self.a.stuffWasDoneTwice())


injector = inject.Injector()
injector.bind(A, scope=inject.appscope)
inject.register(injector)

runTests()

Ideally, I'd like to reset A after each test run, to avoid cross-contamination. (Currently do something like A.reset() in tearDown()..)

inject.reqscope supports something like this (a locally scoped set of instances), but I don't really know where to call register() & unregister() (which resets the injection objet cache). Ot's too late in setUp() and tearDown(), since Foo.a may already be called in Foo.__init__() for each of them.

Any ideas on how to do this, or should I use a different approach?

like image 419
Macke Avatar asked Sep 20 '26 19:09

Macke


1 Answers

You can use setUp and tearDown to register/unregister the scope, treating each test method invocation as a new "request".

With the following changes your sample unit tests pass:

class TestFoo(unittest2.TestCase):

    a = inject.attr('a', A)

    def __init__(self, *n, **kw):
        unittest2.TestCase.__init__(self, *n, **kw)
        self.unit_scope = inject.reqscope

    def setUp(self):
        self.foo = Foo()
        self.unit_scope.register()

    def tearDown(self):
        self.unit_scope.unregister()

    ...

And bind your A instance using inject.reqscope:

injector = inject.Injector()
injector.bind(A, scope=inject.reqscope)
like image 119
samplebias Avatar answered Sep 23 '26 08:09

samplebias



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!