On Thu, Aug 13, 2015 at 17:47 -0400, Kai Groner wrote: > Hi holger, > > Thanks for your response. Sorry I haven't followed up sooner.
same here :) > 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. Please checkout https://pytest.org/latest/plugins.html#hookwrapper-executing-around-other-hooks It should be the right hook to systematically do your with-injector logic. > > 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. You probably need to provide this "login" fixture even if it's empty and work is done in the hook above. not sure i get all your semantics 100 % though. best, holger > > > 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 -- about me: http://holgerkrekel.net/about-me/ contracting: http://merlinux.eu _______________________________________________ pytest-dev mailing list [email protected] https://mail.python.org/mailman/listinfo/pytest-dev
