[Twisted-Python] Global reactor unit tests in the Twisted test suite

Jonathan Lange jml at mumak.net
Mon Nov 7 13:06:59 EST 2011


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)?

jml



More information about the Twisted-Python mailing list