py.test with Twisted and Unhandled Errors

“illegal switch in blockon”

py.test is awesome. I really love the clean testing style it allows, and the flexibility of @fixture s is great.

I find the fixtures especially useful for higher-level testing, like integration or functional tests where you often have something that is expensive to set up (e.g. a Selenium browser instance) that’s perfectly fine to re-use in a bunch of tests.

Anyway, I was getting a weird and inscrutible error message when using py.test along with the twisted plugin

These usually work quite well together, but I found that in some error-cases when my fixture wasn’t getting set up, the pytest.blockon call would simply hang, and a ctrl-c would lead to an odd-sounding error (AssertionError: illegal switch in blockon) but of course formatted nicely around pytest-twisted’s internals.

I even managed to make an SSCCE for it! Happy day!

from twisted.internet.defer import Deferred
from twisted.internet import reactor
import pytest
@pytest.fixture
def foo():
    d = Deferred()
    def blammo():
        raise RuntimeError('foo')
    reactor.callLater(0.1, blammo)
    return pytest.blockon(d)
def test_meaning(foo):
    assert foo == 42

So the short version of the story is that it’s an unhandled exception. The “hanging” makes perfect sense in this context: d is never getting a .callback or .errback triggered on it.

I don’t know py.test internals well enough to suggest anything they can do to improve error-logging in cases like this. If anyone has a suggestion, I’d be glad to know it!

I couldn’t find any information about this on the Internets, so hopefully this saves someone else an hour or two.