Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Dial T for Testing

Dial T for Testing

A talk about testing and Django from the March 2014 DJUGL meetup.

David Winterbottom

March 12, 2014
Tweet

More Decks by David Winterbottom

Other Decks in Programming

Transcript

  1. class TestASignedInUser(WebTestCase):! ! def setUp(self):! self.user = G(User)! self.order =

    factories.create_order(user=self.user)! ! def test_can_see_their_email_address_on_the_profile_page(self):! profile_page = self.app.get(! reverse('customer:summary'), user=self.user)! self.assertTrue(self.email in profile_page.content)! ! def test_can_update_their_name(self):! profile_form_page = self.app.get(! reverse('customer:profile-update'), user=self.user)! form = profile_form_page.forms['profile_form']! form['first_name'] = 'Barry'! form['last_name'] = 'Chuckle'! response = form.submit()! self.assertRedirects(response, reverse('customer:summary'))! ! # Reload user! user = User.objects.get(id=self.user.id)! self.assertEquals("Barry", user.first_name)! self.assertEquals("Chuckle", user.last_name)!
  2. class TestASignedInUser(WebTestCase):! ! def setUp(self):! self.user = G(User)! self.order =

    factoies.create_order(user=self.user)! ! def test_can_see_their_email_address_on_the_profile_page(self):! profile_page = self.app.get(! reverse('customer:summary'), user=self.user)! self.assertTrue(self.email in profile_page.content)! ! def test_can_update_their_name(self):! profile_form_page = self.app.get(! reverse('customer:profile-update'), user=self.user)! form = profile_form_page.forms['profile_form']! form['first_name'] = 'Barry'! form['last_name'] = 'Chuckle'! response = form.submit()! self.assertRedirects(response, reverse('customer:summary'))! ! # Reload user! user = User.objects.get(id=self.user.id)! self.assertEquals("Barry", user.first_name)! self.assertEquals("Chuckle", user.last_name)! System under test
  3. class TestASignedInUser(WebTestCase):! ! def setUp(self):! self.user = G(User)! self.order =

    factories.create_order(user=self.user)! ! def test_can_see_their_email_address_on_the_profile_page(self):! profile_page = self.app.get(! reverse('customer:summary'), user=self.user)! self.assertTrue(self.email in profile_page.content)! ! def test_can_update_their_name(self):! profile_form_page = self.app.get(! reverse('customer:profile-update'), user=self.user)! form = profile_form_page.forms['profile_form']! form['first_name'] = 'Barry'! form['last_name'] = 'Chuckle'! response = form.submit()! self.assertRedirects(response, reverse('customer:summary'))! ! # Reload user! user = User.objects.get(id=self.user.id)! self.assertEquals("Barry", user.first_name)! self.assertEquals("Chuckle", user.last_name)! Specification
  4. from nose.plugins.attrib import attr! ! ! @attr('shipping')! class TestFreeShippping(TestCase):! !

    def test_is_free_for_empty_basket(self):! ...! ! ! class TestFixedPriceShipping(TestCase):! ! @attr(slow=True)! def test_returns_fixed_price_for_basket(self):! ...!
  5. from nose.plugins.attrib import attr! ! ! @attr('shipping')! class TestFreeShippping(TestCase):! !

    def test_is_free_for_empty_basket(self):! ...! ! ! class TestFixedPriceShipping(TestCase):! ! @attr(slow=True)! def test_returns_fixed_price_for_basket(self):! ...! Wrap a class
  6. from nose.plugins.attrib import attr! ! ! @attr('shipping')! class TestFreeShippping(TestCase):! !

    def test_is_free_for_empty_basket(self):! ...! ! ! class TestFixedPriceShipping(TestCase):! ! @attr(slow=True)! def test_returns_fixed_price_for_basket(self):! ...! Wrap a method
  7. 0 4 8 12 16 20 24 Focus / flow

    / “zone” Test suite time (seconds)
  8. 0 4 8 12 16 20 24 Focus / flow

    / “zone” Test suite time (seconds) Pre-commit hook?
  9. 0 4 8 12 16 20 24 Focus / flow

    / “zone” Test suite time (seconds)
  10. import mock! from django.utils.functional import curry! ! no_database = curry(!

    mock.patch, 'django.db.backends.util.CursorWrapper',! Mock(side_effect=RuntimeError(! "Using the database is not permitted")))! ! ! @no_database()! class AUnitTest(TestCase):! ...! http://bit.ly/126vPrt
  11. import mock! from django.utils.functional import curry! ! no_database = curry(!

    mock.patch, 'django.db.backends.util.CursorWrapper',! Mock(side_effect=RuntimeError(! "Using the database is not permitted")))! ! ! @no_database()! class AUnitTest(TestCase):! ...! http://bit.ly/126vPrt Currying mock.patch!
  12. import mock! from django.utils.functional import curry! ! no_database = curry(!

    mock.patch, 'django.db.backends.util.CursorWrapper',! Mock(side_effect=RuntimeError(! "Using the database is not permitted")))! ! ! @no_database()! class AUnitTest(TestCase):! ...! http://bit.ly/126vPrt Wrap classes/methods
  13. class TestBasket(TestCase):! ! def test_add_items(self):! # Create products! product_class =

    ProductClass(! name="Books", require_shipping=True)! product1 = Product.objects.create(title="My first book")! product2 = Product.objects.create(title="My second book")! partner = Partner.objects.create(name="Book Partner")! stockrecord1 = StockRecord(! price_excl_tax=D('12.00'), partner=partner)! stockrecord2 = StockRecord(! price_excl_tax=D('14.00'), partner=partner)! ! # Add to basket! basket = Basket()! basket.add(product1)! basket.add(product2)! ! total = basket.total_excl_tax! ! self.assertEqual(D('26.00'), total)! self.assertEqual(basket.num_lines, 2)! self.assertFalse(basket.is_empty)!
  14. class TestBasket(TestCase):! ! def test_add_items(self):! # Create products! product_class =

    ProductClass(! name="Books", require_shipping=True)! product1 = Product.objects.create(title="My first book")! product2 = Product.objects.create(title="My second book")! partner = Partner.objects.create(name="Book Partner")! stockrecord1 = StockRecord(! price_excl_tax=D('12.00'), partner=partner)! stockrecord2 = StockRecord(! price_excl_tax=D('14.00'), partner=partner)! ! # Add to basket! basket = Basket()! basket.add(product1)! basket.add(product2)! ! total = basket.total_excl_tax! ! self.assertEqual(D('26.00'), total)! self.assertEqual(basket.num_lines, 2)! self.assertFalse(basket.is_empty)! Bad naming
  15. class TestBasket(TestCase):! ! def test_add_items(self):! # Create products! product_class =

    ProductClass(! name="Books", require_shipping=True)! product1 = Product.objects.create(title="My first book")! product2 = Product.objects.create(title="My second book")! partner = Partner.objects.create(name="Book Partner")! stockrecord1 = StockRecord(! price_excl_tax=D('12.00'), partner=partner)! stockrecord2 = StockRecord(! price_excl_tax=D('14.00'), partner=partner)! ! # Add to basket! basket = Basket()! basket.add(product1)! basket.add(product2)! ! total = basket.total_excl_tax! ! self.assertEqual(D('26.00'), total)! self.assertEqual(basket.num_lines, 2)! self.assertFalse(basket.is_empty)! Heavy set-up
  16. class TestBasket(TestCase):! ! def test_add_items(self):! # Create products! product_class =

    ProductClass(! name="Books", require_shipping=True)! product1 = Product.objects.create(title="My first book")! product2 = Product.objects.create(title="My second book")! partner = Partner.objects.create(name="Book Partner")! stockrecord1 = StockRecord(! price_excl_tax=D('12.00'), partner=partner)! stockrecord2 = StockRecord(! price_excl_tax=D('14.00'), partner=partner)! ! # Add to basket! basket = Basket()! basket.add(product1)! basket.add(product2)! ! total = basket.total_excl_tax! ! self.assertEqual(D('26.00'), total)! self.assertEqual(basket.num_lines, 2)! self.assertFalse(basket.is_empty)! Noise
  17. class TestBasket(TestCase):! ! def test_add_items(self):! # Create products! product_class =

    ProductClass(! name="Books", require_shipping=True)! product1 = Product.objects.create(title="My first book")! product2 = Product.objects.create(title="My second book")! partner = Partner.objects.create(name="Book Partner")! stockrecord1 = StockRecord(! price_excl_tax=D('12.00'), partner=partner)! stockrecord2 = StockRecord(! price_excl_tax=D('14.00'), partner=partner)! ! # Add to basket! basket = Basket()! basket.add(product1)! basket.add(product2)! ! total = basket.total_excl_tax! ! self.assertEqual(D('26.00'), total)! self.assertEqual(basket.num_lines, 2)! self.assertFalse(basket.is_empty)! Unclear assertions
  18. class TestBasket(TestCase):! ! def test_add_items(self):! # Create products! product_class =

    ProductClass(! name="Books", require_shipping=True)! product1 = Product.objects.create(title="My first book")! product2 = Product.objects.create(title="My second book")! partner = Partner.objects.create(name="Book Partner")! stockrecord1 = StockRecord(! price_excl_tax=D('12.00'), partner=partner)! stockrecord2 = StockRecord(! price_excl_tax=D('14.00'), partner=partner)! ! # Add to basket! basket = Basket()! basket.add(product1)! basket.add(product2)! ! total = basket.total_excl_tax! ! self.assertEqual(D('26.00'), total)! self.assertEqual(basket.num_lines, 2)! self.assertFalse(basket.is_empty)! Sloppy coding
  19. class TestBasketTotal(TestCase):! ! def setUp(self):! self.basket = Basket()! ! def

    test_is_correct_after_adding_multiple_items(self):! products = [! factory.create_product(price_excl_tax=D('12.00')),! factory.create_product(price_excl_tax=D('14.00')),! ]! for product in products:! self.basket.add_product(product)! self.assertEqual(! D('12.00') + D('14.00'), self.basket.total_excl_tax)!
  20. class TestBasketTotal(TestCase):! ! def setUp(self):! self.basket = Basket()! ! def

    test_is_correct_after_adding_multiple_items(self):! products = [! factory.create_product(price_excl_tax=D('12.00')),! factory.create_product(price_excl_tax=D('14.00')),! ]! for product in products:! self.basket.add_product(product)! self.assertEqual(! D('12.00') + D('14.00'), self.basket.total_excl_tax)! Descriptive names
  21. class TestBasketTotal(TestCase):! ! def setUp(self):! self.basket = Basket()! ! def

    test_is_correct_after_adding_multiple_items(self):! products = [! factory.create_product(price_excl_tax=D('12.00')),! factory.create_product(price_excl_tax=D('14.00')),! ]! for product in products:! self.basket.add_product(product)! self.assertEqual(! D('12.00') + D('14.00'), self.basket.total_excl_tax)! Factory functions
  22. class TestBasketTotal(TestCase):! ! def setUp(self):! self.basket = Basket()! ! def

    test_is_correct_after_adding_multiple_items(self):! products = [! factory.create_product(price_excl_tax=D('12.00')),! factory.create_product(price_excl_tax=D('14.00')),! ]! for product in products:! self.basket.add_product(product)! self.assertEqual(! D('12.00') + D('14.00'), self.basket.total_excl_tax)! Intention revealing
  23. WebTest webtest.readthedocs.org/ def test_contact_us(self):! home = self.app.get('/')! ! # Fill

    in form! contact_us = home.click(linkid="contact_us_link")! form = contact_us.forms['profile_form']! form['name'] = 'Barry Chuckle'! form['query'] = 'To me?'! confirm = form.submit().follow()! ! self.assertTrue('Thanks Barry' in confirm.content)!
  24. •Test suite is there to help you •Make it clear

    and easy to read •Make it fast •Master your test runner TLDR