Reputation: 512
The code below fails because twisted.trial.unittest.TestCase, the desired baseclass, is not the baseclass.
from twisted.trial import unittest
from unittest import TestCase
import myapp
class Feature(TestCase):
def setUp(self):
self.callbackCounter = 0
def checkCbCalled(self, expected):
self.assertEqual(self.callbackCounter, expected)
def testTrialCallsDeferred(self):
d = myapp.buildFeature()
self.addCleanup(self.checkCbCalled, expected=1)
def cb(res):
self.callbackCounter += 1
d.addCallback(cb).addErrback(self.fail)
return d # does not fire because of 'import rules'?
If I had said
from twisted.trial import unittest as trialut
from trialut import TestCase
or, better:
from twisted.trial.unittest import TestCase
then the test would run as expected and trial.unittest.TestCase would have fired my deferred.
This seems as though the local recently imported thing should have superceded the one available in {lib/pythonX.X/unittest}. I understand it must be a rule based on sys.path or something else implicit or explicit. This tripped me up for a little too long because I did not have the call to addCleanup and all tests were passing because returned deferred instance was not being fired.
I broke some rule(s), Please advise some reading or other.
Thanks Mike
Upvotes: 1
Views: 249
Reputation: 48335
It's very unclear how you expect this to work, but it sounds like you're at least somewhat confused about how modules in Python behave.
An import
statement (sometimes) loads a module from a source file and then binds a name in the local scope to that module object.
So, when you do:
from twisted.trial import unittest
You're loading the twisted.trial.unittest
module and then binding the local name unittest
it.
This interacts in no interesting way with the following statement:
from unittest import TestCase
which loads the unittest
module and then binds the local name TestCase
to the object referred to by that module's TestCase
attribute.
When you later subclass TestCase
:
class Feature(TestCase):
...
you're making straightforward use of the name TestCase
in your local scope - a name which refers to the TestCase
class defined by the unittest
module. Notice that it has nothing at all to do with Twisted's twisted.trial.unittest
module, even though you've loaded that module too. You have to use one of its attributes in order to use its functionality.
One change to make to improve the behaviour of your code is to simply stop using the standard libraryunittest
module at all. Delete this line:
from unittest import TestCase
And replace your class definition with:
class Feature(unittest.TestCase):
Don't get confused by the fact that the standard library unittest
module shares part of the name of the Twisted twisted.trial.unittest
module. They are different modules with different (though similar, sometimes overlapping) features. The class definition in the example above is using twisted.trial.unittest
, because it comes after your original line:
from twisted.trial import unittest
Once you are actually using Twisted's TestCase
(from twisted.trial.unittest
) and not the standard library's TestCase
(from unittest
), you'll get the behaviour you expect when a test method returns a Deferred
. This is because it's Twisted that provides this feature, not the standard library.
Upvotes: 2