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.

Avatar for David Winterbottom

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