3

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?

Macke
  • 24,812
  • 7
  • 82
  • 118

1 Answers1

1

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)
samplebias
  • 37,113
  • 6
  • 107
  • 103
  • I tried something like that, because it seemed the most intuitive solution, but it seemed like the register() call was made too late for things to work properly. I'll have a go at it again. – Macke Jun 01 '11 at 07:04
  • Well, this worked excellently. I must've missed some detail in my own attempt. Thanks for getting everything correct! – Macke Jun 01 '11 at 07:18
  • Cool I'm glad it was helpful! The order of operations caused by `Inject`-ing classes can be tricky to trace. – samplebias Jun 01 '11 at 15:44