On Tue, Sep 08, 2015 at 14:33 -0400, Kai Groner wrote: > On Mon, Sep 7, 2015 at 4:01 AM, holger krekel <[email protected]> wrote: > > > 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. > > > I think so. I just need to get it to run the test without certain > "fixtures". > > > > 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. > > > > The thing is that these aren't really fixtures and the dependencies are > selected by annotation rather than argument name. What login means in one > test won't match what login means in another test. Even when it is the > same service, it will be a new instance/partial created by a new injector > with new services. > > I do want to use py.test fixtures for parametrization. Is there a way I > can tell py.test that certain arguments aren't fixtures and it shouldn't > worry about providing them?
Not really. Why can't you have a fixture function that selects an implementation based on annotations associated with the test function? holger _______________________________________________ pytest-dev mailing list [email protected] https://mail.python.org/mailman/listinfo/pytest-dev
