How to unit-test an event loop?
I'm programming an HTTP proxy in Python (transparent proxy for request/response monitoring). But as a TDD adopter, I'm starting the project with HTTP inputs that should be caught by a TCP server. But, as any server, it must run within an event loop, so that it can listen in a specific port.
Well, since starting the event loop will keep the interpreter inside the loop, after starting the server from a unit test, I开发者_运维知识库 cannot come back to the test to send an HTTP request to this server.
What do you guys recommend me to design so that I can run the server and come back to the unit test to test it? Use threads? Zero-timeouts?
Thanks!
Diogo
You need to refactor whatever your loop listens to so that you can replace that with a fake or mock. If that object is not derived from an interface, you might have to write a wrapper object that you can fake or mock.
Regarding the looping problem: Multithreading would indeed be a possible solution.
The loop itself shouldn't be covered by the TDD. You can test mostly everything else, and, given that the code within the loop is properly isolated, you can be confident on your code.
That is, if your loop is reduced to simply
while keep_serving:
keep_serving = handle_events(...)
you can test handle_events and its components, and the loop itself is trivial.
Also, you'll be faced with having to test connections, sockets, etc. I recommend the excellent Mocker module, by Gustavo Niemeyer. It's very handy (if non-trivial to fully understand at first sight).
unit testing is more about testing things at the function level, an integration test is more of an "end to end" type thing. If your function has dependencies that you can't really get around, it is a good time to find a mocking framework for your platform.
The most natural way: write your test clients using the same event handling framework as your server (no different than writing any other client/server code).
Then, each unit test would look roughly like:
- Register the test server's socket listener
- Register the test client's socket connector
- Start the event loop, waiting for the interaction to complete (or time out)
- Process/report the test results
In most cases, it would be the responsibility the test client to determine when the test is complete and signal the event loop to exit, but this can depend on the test. Your would also probably want to write standardized timeout handlers to fail the test (same as you would with blocking I/O).
精彩评论