Hi holger, Thanks for your response. Sorry I haven't followed up sooner.
On Thu, May 7, 2015 at 7:21 AM, holger krekel <[email protected]> wrote: > Hi Kai, > > On Thu, Apr 30, 2015 at 19:28 -0400, Kai Groner wrote: > > I'm trying to figure out how I can test a code base that uses an existing > > dependency injection system. I've run into two problems, and I have > > solutions for each of them but I think maybe there is a better way, so > I'm > > looking for some advice. > > Could you provide a simple abstract example? > Here and also in the following i don't really understand the background. > The DI system we are using is called jeni. I'll try to keep things simple here so you don't need to know a lot about it, but here's the url. https://github.com/rduplain/jeni-python This is untested code, that I hope will be illustrative. If you think it would be helpful to run it, let me know and I will make sure it works. We write code sort of like this: @route('login', method='POST') @jeni.annotate def login( username: 'form:username', password: 'form:password', user_lookup: 'user_lookup', session_init: 'session_init'): user = user_lookup(username) if user is None: raise ValueError if not user.check_password(password): raise ValueError session_init(user) Here is an example of an injector prototyped with a trivial user_lookup implementation: class Injector(jeni.Injector): pass @Injector.factory def user_lookup_factory(): class User: def __init__(self, username, password=None): self.username, self.password = username, password def check_password(self, password): return password == self.password def user_lookup(username): return User(username, username) Calling this, looks like: with Injector() as inj: inj.apply(login) There is a partial application mechanism, that creates a wrapper that resolves injector bindings at call time. @jeni.annotate def test_login(login: jeni.partial(login)): login(username='kai', password='kai') with raises(LookupError): login(username='kai', password='KAI') with Injector() as inj: inj.apply(test_login) Because we need to write a lot of tests, I want to avoid writing the with block with every test. I thought maybe I could use py.test hooks to do this. > The first problem is how do I override how a test using this injector is > > called? I think I want to use the pytest_runtest_call hook, but it still > > tries to invoke the test without the injector. My current solution is to > > use the experimental hookwrapper mechanism to replace item.obj with a > > partially bound version, then restore it afterward. > Here my problem is that py.test looks for a ``login`` fixture and when it finds none it decides the test cannot proceed. > > The second problem I'm having is the py.test fixture system is trying to > > resolve arguments that are provided by this other injector. How can I > tell > > it that some of these don't need to be provided? My current solution is > to > > blind py.test with a wrapper function with a *a, **kw signature. I use > > functools.wraps, so annotations are introspectable for the other > injector, > > and delete the __wrapped__ attribute to prevent py.test from > introspecting > > it. Is there a nicer, and perhaps less blunt, way to influence the > funcarg > > fixture behaviors? I've tried a couple things with the > > pytest_collection_modifyitems hook, but haven't gotten anything that > works > > yet. > > > > Other details to know about this injection system: > > - we want to build and teardown the injector with each test > > - we may want to configure the injector differently for some tests > > (possibly with fixture data from py.test) Kai
_______________________________________________ pytest-dev mailing list [email protected] https://mail.python.org/mailman/listinfo/pytest-dev
