Question

I'm trying to figure out how to write a trial test case which asserts an exception is raised.

Currently I have 2 simple methods to test (success and failure). Each method returns a deferred which has already been either callback'd or errback'd. Testing the success method works fine. When testing the failure method I expect to be able to assert that an exception was raised (using assertRaises).

However the test case fails and I get:

twisted.trial.unittest.FailTest: ConnectionRefusedError not raised (<Deferred at 0x920e28c current result: <twisted.python.failure.Failure <class 'twisted.internet.error.ConnectionRefusedError'>>> returned)

The code is as follows:

from twisted.trial.unittest import TestCase
from twisted.internet.defer import inlineCallbacks, succeed, fail
from twisted.internet.error import ConnectionRefusedError

class MyObject:
    def success(self):
        return succeed(True)

    def failure(self):
        return fail(ConnectionRefusedError())


class TestErrBack(TestCase):
    def setUp(self):
        self.o = MyObject()

    @inlineCallbacks
    def test_success(self):
        result = yield self.o.success()
        self.assertTrue(result)

    @inlineCallbacks
    def test_failure(self):
        # this test case is failing !
        yield self.assertRaises(ConnectionRefusedError, self.o.failure)

Am I using the right approach in test_failure ? I can use try...catch around the call to self.o.failure, but I don't think this approach is as good as using assertRaises.

Was it helpful?

Solution

Use TestCase.assertFailure instead:

yield self.assertFailure(self.o.failure(), ConnectionRefusedError)

Starting in Twisted 12.3, there's also a TestCase.failureResultOf helper:

self.failureResultOf(self.o.failure()).trap(ConnectionRefusedError)

And starting in 13.1 this API takes an additional argument and performs type checking for you:

self.failureResultOf(self.o.failure(), ConnectionRefusedError)

This is useful for tests where you know the Deferred has already fired with a result. If the Deferred does not have a failure result at the time of the call, failureResultOf raises a test-failing exception instead of returning the failure.

This will work fine for your example code and should be applicable to most unit tests. If you're using trial to write functional or integration tests where there is actual asynchronous work going on and you don't know when the Deferred will fire then you need to stick with the first API, assertFailure.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top