PSP, XP, TDD and other methodologies for solitary programmers

Changjune Kim juneaftn at REMOVETHIShanmail.net
Thu Jan 2 22:07:34 EST 2003


"Brad Clements" <bkc at Murkworks.com> wrote in message
news:3e14a219$1_1 at goliath.newsgroups.com...
> _
> "Terry Reedy" <tjreedy at udel.edu> wrote in message
> news:aJWcnRWzQtc7E4mjXTWcqA at comcast.com...
>
> > For those who missed the reference in a recent thread, there is an
> > online PDF prepublication version of Kent Beck's new book Test-Driven
> > Develoopment By Example:
> >
> > http://groups.yahoo.com/group/testdrivendevelopment/files/TDD17Jul2002
> > .pdf
> >
>
> This is where I learned the most about TDD. And, I've implemented
unittests,
> but as I said in my previous post, I'm looking for test patterns
suiteable
> for database backed "objects".
>
> The .pdf referenced above does have some patterns, but I'm looking for
more
> ideas on database testing.. In my previous post I mentioned the "mock
> object" I used to capture SQL statements.. But that still doesn't test
the
> db dump/load aspect of my objects.
>
> I guess there's no getting around actually looking at the database after
> storing an object..
>
> I'll probably use temporary tables and set them up in the fixture.
>

As others have recommended, you don't want to test everything within a real
db -- it's too expensive.

Keep the layers separate and test models enough so that you have confidence
in the business layer. If in doubt, test the primitive operations of your
persistence layer with real dbs. Don't do all the combinations.

If you are doing acceptance testing or something, consider using
"golden/silver/bronze db method." Golden DB is the product db, and Silver
DB is for the integration, and Bronze DB is for individual, uh pair,
developers, which is on every development machine. Manage the three dbs
separately.

Make use of scripts and change-control(CVS,...) the DB's schema and
scripts. Try to automate repititive works. DRY.

> Speaking of TestCase, I though that setUp would be called only once for
all
> test* included in the class, but I find that setUp() is called for ever
test
> case in the same class.
>
> What I want is one instance of the TestCase to be created (hence, one
call
> to setUp()), then each test* case to be run in that TestCase instance.
>
> I guess I'll need to make up something to do it that way, since setting
up a
> temporary database table for every test in my suite will be expensive.

Try to make each test case as independent as possible. However, if you
can't really do with the  expensive cost of setups...

As someone else has suggested, use module space. Or you could use class
space -- as class attributes and factory method with singleton.

Or you could use the following decorator which I made and nowadays am not
using quite often.

----

import unittest, pdb, sys

class Test1(unittest.TestCase):
    def setUp(self):
        print "setUp..."
    def test1(self):
        pass
    def test2(self):
        pass
    def tearDown(self):
        print "tearing"

class TestDecorator(unittest.TestSuite):
    def __init__(self,aSuite):
        unittest.TestSuite.__init__(self,tests=aSuite._tests)
        self._suite=aSuite
        self._tests=self._suite._tests
    def __repr__(self):
        return "<%s tests=%s>" % (self.__class__, self._suite._tests)
    def shortDescription(self):
        doc = self.__doc__
        return doc and string.strip(string.split(doc, "\n")[0]) or None
    def setUp(self):
        pass
    def tearDown(self):
        pass
    def __call__(self,result):
        try:
            self.setUp()
        except:
            result.addError(self, self.__exc_info())
            return
        self._suite.run(result)
        try:
            self.tearDown()
        except:
            result.addError(self, self.__exc_info())
            return
    def __exc_info(self):
        exctype, excvalue, tb = sys.exc_info()
        if sys.platform[:4] == 'java': ## tracebacks look different in
Jython
            return (exctype, excvalue, tb)
        newtb = tb.tb_next
        if newtb is None:
            return (exctype, excvalue, tb)
        return (exctype, excvalue, newtb)

class DBTest(TestDecorator):
    def setUp(self):
        print "connecting to the db..."
    def tearDown(self):
        print "disconnecting from the db..."

def suite():
    suite = unittest.defaultTestLoader.loadTestsFromName('__main__')
    #or test1=unittest.defaultTestLoader.loadTestsFromTestCase(TestOne)
    return DBTest(suite)

if __name__=='__main__':
    unittest.main(defaultTest="suite")
    runner = unittest.TextTestRunner()
    runner.run(suite())

----
running this code outputs:

connecting to the db...
setUp...
tearing
.setUp...
tearing
.disconnecting from the db...

----------------------------------------------------------------------
Ran 2 tests in 0.016s

OK






More information about the Python-list mailing list