[Twisted-Python] Global reactor unit tests in the Twisted test suite
exarkun at twistedmatrix.com
exarkun at twistedmatrix.com
Mon Nov 7 13:25:36 EST 2011
On 06:06 pm, jml at mumak.net wrote:
>On Tue, Nov 1, 2011 at 6:48 PM, Glyph <glyph at twistedmatrix.com> wrote:
>>On Nov 1, 2011, at 12:14 PM, Phil Mayers wrote:
>>>On 01/11/11 15:28, Christopher Armstrong wrote:
>>>>I whole-heartedly agree with the sentiment, though. We need to get
>>>>rid
>>>>of the global reactor.
>>>
>>>Why?
>>
>>Sometimes you want a different reactor. The most common reason is
>>unit testing, although if we could successfully eliminate the global
>>reactor everywhere, there are other things that we might be able to
>>do: slowing down or speeding up time from a protocol's perspective (by
>>replacing IReactorTime), grouping related objects together in reactors
>>that can be shut down together (so that reactor.stop() doesn't
>>actually end the process); or, similarly, suspending a group of
>>related objects (removeReader()/removeWriter() on everything) so that
>>they can be inspected for debugging purposes, without suspending the
>>thing doing the inspecting (a manhole python prompt).
>>>I find the "pass reactor as 1st argument to everything" API pattern
>>>messy. I'm sure there's a good reason. What is it?
>>
>>This pattern is a solution to the problem, but I agree that it is
>>possibly not the optimal solution. It sort of points in a direction
>>where every possible module that might be imported becomes an argument
>>to your function. After all, there are plenty of other modules which
>>have to be mocked for testing, why not just make everyone's __init__
>>method take sys.modules as an argument too, and never import anything?
>>In more complex systems this can definitely turn into a bit of a mess.
>>
>>Nevertheless, "real reactor as default argument" is not a huge
>>improvement either, because it typically breaks one level out. If you
>>have 'a(reactor=defaultReactor)' and then 'b()' needs to call 'a',
>>half the time 'b' will forget to supply a reactor argument and call
>>'a()' passing nothing, because that appears to be the suggested API.
>>Any code that calls 'b()' then needs to deal with the fact that the
>>global reactor is going to get used, even if it has a cleanly
>>encapsulated parameter of its own. With sufficient discipline, of
>>course, this approach is equivalent.
>...
>>If you can think of a better solution that addresses all of these
>>concerns simultaneously somehow, please share, I'd love to hear it
>>:-).
>
>reactor = getUtility(IReactor)?
That's not really a solution. It's the barest glimpse of a large system
which might be applied as a solution. Do you want to expand it?
Jean-Paul
More information about the Twisted-Python
mailing list