Testing in Hard to Reach Places            Lee Begg           Begg Digital
Overview●   Goals●   The module●   Refactoring●   SqlAlchemy tricks●   Mocking hard things      Code: http://github.com/ll...
Goals●   Make sure it works properly    ●   All the time    ●   In all conditions●   Unit testing to check    ●   Cover 10...
Example module  def main():    Check the tripwire, email if the latest values have an RMS value over 2    session = model....
Refactoring●   Refactor out components to testclass RMSTest(unittest.TestCase):   Test the RMS calculations    def testRMS...
SqlAlchemy Tricks●   Change the database in the unittest setUp    method●   Done internally by Django#override database se...
SqlAlchemy Tricksclass DatabaseTestSetup(object):   Create the database in the setUp, and drop it in tearDown  Used to abs...
SqlAlchemy Tricksclass ModelTest(DatabaseTestSetup, unittest.TestCase):   Test the model classes  def testMeasuredValueTab...
Mock●   Creating fake “mock” objects/classes/modules●   Replace things you couldnt normally control●   A few frameworks av...
Mock exampleclass SendEmailTest(unittest.TestCase):   Test sending email  def testSendEmail(self):    tt = minimock.TraceT...
Upcoming SlideShare
Loading in...5
×

Testing in those hard to reach places

979

Published on

KiwiPyCon2011, Wellington, Sunday, Track 1, Testing in those hard to reach places by Lee Begg

Published in: Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total Views
979
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
6
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Testing in those hard to reach places

  1. 1. Testing in Hard to Reach Places Lee Begg Begg Digital
  2. 2. Overview● Goals● The module● Refactoring● SqlAlchemy tricks● Mocking hard things Code: http://github.com/llnz/kiwipycon2011testing Slides: http://www.beggdigital.com/media/kiwipycon2011testing.pdf
  3. 3. Goals● Make sure it works properly ● All the time ● In all conditions● Unit testing to check ● Cover 100% ● Might still miss cases
  4. 4. Example module def main(): Check the tripwire, email if the latest values have an RMS value over 2 session = model.Session() values = session.query(model.MeasuredValue).order_by(model.MeasuredValue.desc()).limit(20).all() totalsq = 0 for value in values: totalsq += value.value**2 rms = math.sqrt(totalsq) if rms > 2: body = """Database trip wire has been trippedRMS value was: %s""" subject = "Tripwire report %s" % datetime.date.today() msg = MIMEText(body) msg[Subject] = [DBTW] %s % subject msg[To] = ,.join(settings.TO_ADDRESSES) msg[From] = settings.FROM_ADDRESS server = smtplib.SMTP(localhost) result = server.sendmail(settings.FROM_ADDRESS, settings.TO_ADDRESSES, msg.as_string()) if len(result) != 0: print "sendmail failures: %s" % result server.quit()
  5. 5. Refactoring● Refactor out components to testclass RMSTest(unittest.TestCase): Test the RMS calculations def testRMSCalc(self): def calcRMS(values): testvalues = [ totalsq = 0.0 ([0], 0), for value in values: ([1], 1), totalsq += value**2 ([2], 2), ([0, 0], 0), rms = math.sqrt(totalsq/len(values)) ([1, 1], 1), return rms ([0] * 20, 0), ([1] * 20, 1), ([0, 0, 0, 1], 0.5), ([3, 1, 3, 0, 1], 2), ] for values, expected in testvalues: result = tripwire.calcRMS(values) self.assertAlmostEqual(result, expected, msg=rmsCalc(%s) gave %s,expected %s % (values, result, expected))
  6. 6. SqlAlchemy Tricks● Change the database in the unittest setUp method● Done internally by Django#override database settingfrom dbtripwire import settingssettings.DATABASE_URL = sqlite:///:memory:from dbtripwire.model import initDatabase, dropDatabase
  7. 7. SqlAlchemy Tricksclass DatabaseTestSetup(object): Create the database in the setUp, and drop it in tearDown Used to abstract this away from all the unittests that use the Database. Must be the first class inherited from, or TestCase will override these methods, not the other way around. def setUp(self): Initialise the database with the tables initDatabase() def tearDown(self): Drop the tables dropDatabase()
  8. 8. SqlAlchemy Tricksclass ModelTest(DatabaseTestSetup, unittest.TestCase): Test the model classes def testMeasuredValueTable(self): MeasuredValue table test session = model.Session() self.assertEqual(session.query(model.MeasuredValue).count(), 0) mv = model.MeasuredValue(5) self.assert_(mv) session.add(mv) session.commit() self.assertEqual(session.query(model.MeasuredValue).count(), 1) mv1 = session.query(model.MeasuredValue).one() self.assertEqual(mv1.id, 1) self.assertEqual(mv1.value, 5) #dont forget to test the __repr__ string self.assertEqual(repr(mv1), "<MeasuredValue(1, 5)>") session.delete(mv1) session.commit() self.assertEqual(session.query(model.MeasuredValue).count(), 0)
  9. 9. Mock● Creating fake “mock” objects/classes/modules● Replace things you couldnt normally control● A few frameworks available● Very useful in replacing network connections ● Httplib for example ● Smtplib for another
  10. 10. Mock exampleclass SendEmailTest(unittest.TestCase): Test sending email def testSendEmail(self): tt = minimock.TraceTracker() smtpconn = minimock.Mock(smtplib.SMTP, tracker=tt) minimock.mock(smtplib.SMTP, mock_obj=smtpconn) smtpconn.mock_returns = smtpconn smtpconn.sendmail.mock_returns = {} tripwire.sendEmail(2.5, datetime.date(2011, 8, 16)) expected = r"""Called smtplib.SMTP(localhost)Called smtplib.SMTP.sendmail( lee@beggdigital.co.nz, [lee@beggdigital.co.nz, llnz@paradise.net.nz], Content-Type: text/plain; charset="us-ascii"nMIME-Version: 1.0nContent-Transfer-Encoding:7bitnSubject: [DBTW] Tripwire Report 2011-08-16nTo: lee@beggdigital.co.nz,llnz@paradise.net.nznFrom: lee@beggdigital.co.nznnDatabase trip wire has been tripped.nnRMSvalue was: 2.5n)Called smtplib.SMTP.quit()""" self.assertTrue(tt.check(expected), tt.diff(expected)) minimock.restore()
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×