Unit testing and technology spikes
As part of object-oriented design, we'll often create technology spike modules that look like the code shown in this section. We'll break it down into three sections. First, we have the overall abstract test as follows:
import types import unittest class TestAccess( unittest.TestCase ): def test_should_add_and_get_attribute( self ): self.object.new_attribute= True self.assertTrue( self.object.new_attribute ) def test_should_fail_on_missing( self ): self.assertRaises( AttributeError, lambda: self.object.undefined )
This abstract TestCase
subclass defines a few tests that we're expecting a class to pass. The actual object being tested is omitted. It's referenced as self.object
, but no definition is provided, making this TestCase
subclass abstract. A setUp()
method is required by each concrete subclass.
The following are three concrete TestAccess
subclasses that will exercise three different kinds of objects:
class SomeClass: pass class Test_EmptyClass( TestAccess ): def setUp( self ): self.object= SomeClass() class Test_Namespace( TestAccess ): def setUp( self ): self.object= types.SimpleNamespace() class Test_Object( TestAccess ): def setUp( self ): self.object= object()
The subclasses of the TestAccess
classes each provide the required setUp()
method. Each method builds a different kind of object for testing. One is an instance of an otherwise empty class. The second is an instance of types.SimpleNamespace
. The third is an instance of object
.
In order to run these tests, we'll need to build a suite that doesn't allow us to run the TestAccess
abstract test.
The following is the rest of the spike:
def suite(): s= unittest.TestSuite() s.addTests( unittest.defaultTestLoader.loadTestsFromTestCase(Test_EmptyClass) ) s.addTests( unittest.defaultTestLoader.loadTestsFromTestCase(Test_Namespace) ) s.addTests( unittest.defaultTestLoader.loadTestsFromTestCase(Test_Object) ) return s if __name__ == "__main__": t= unittest.TextTestRunner() t.run( suite() )
We now have concrete evidence that the object
class can't be used the same way the types.SimpleNamespace
class can be used. Further, we have a simple test class that we can use to demonstrate other designs that work (or don't work.) The tests, for example, demonstrate that types.SimpleNamespace
behaves like an otherwise empty class.
We have omitted numerous details of potential unit test cases. We'll look at testing in depth in Chapter 15, Designing for Testability.