token testing slides

87
Token Testing Talk Eric Holscher http://ericholscher.com Djangocon 2009

Upload: ericholscher

Post on 14-Jan-2015

6.429 views

Category:

Technology


0 download

DESCRIPTION

A rehash of my previous Django testing talk with a bit of content added.

TRANSCRIPT

Page 1: Token  Testing Slides

Token Testing TalkEric Holscher

http://ericholscher.comDjangocon 2009

Page 2: Token  Testing Slides

0

2.5

5.0

7.5

10.0

Pycon RailsConf DjangoCon

Testing Talks per Conference

Page 3: Token  Testing Slides

How do you know?

» First 4 months of my job was porting and testing Ellington

» Going from Django r1290 to Django 1.0.

» Suite from 0 to 400 tests. (Now has 1715)

Page 4: Token  Testing Slides

30,000 Ft View

»State of testing in Django

»Why you should be testing

»How you start testing

»Useful tools

»Eventual Goals

Page 5: Token  Testing Slides

State of Django Testing

Page 6: Token  Testing Slides

assertTrue('Hello World', community.testing.status)

Page 7: Token  Testing Slides

Django 1.1

Making Testing Possible since 2009

Page 8: Token  Testing Slides

manage.py startapp creates a tests.py

Page 9: Token  Testing Slides

Basic Test

from django.test import TestCase

class SimpleTest(TestCase): def test_basic_addition(self): """ Tests that 1 + 1 always equals 2. """ self.failUnlessEqual(1 + 1, 2)

__test__ = {"doctest": """Another way to test that 1 + 1 is equal to 2.

>>> 1 + 1 == 2True"""}

Page 10: Token  Testing Slides

Fast Tests(Transactions)

Page 11: Token  Testing Slides

0

15

30

45

60

Django 1.0 Django 1.1

Ellington Test Speedup

Minutes (Lower is better)

Page 12: Token  Testing Slides

You now have no excuse.

Page 13: Token  Testing Slides

Why to test

Page 14: Token  Testing Slides

Scary

Page 15: Token  Testing Slides

Less Scary

Page 16: Token  Testing Slides

Not Scary

Page 17: Token  Testing Slides

Peace of Mind

Page 18: Token  Testing Slides

Code must adapt

Page 19: Token  Testing Slides

“It is not the strongest of the species that survives, nor the most intelligent, but the

one most responsive to change.

- Charles Darwin

Page 20: Token  Testing Slides

Won’t somebody please think of the users?!

Page 21: Token  Testing Slides

Tests as Documentation

Page 22: Token  Testing Slides

Tests as Documentation

Test driven development +

Document driven development=

Test Driven Documentation

Page 23: Token  Testing Slides

“Code without tests is broken as designed

- Jacob Kaplan-Moss

Page 24: Token  Testing Slides

Dizzying Array of Testing Options

Page 25: Token  Testing Slides

What kind of test?

» doctest

» unittest

Page 26: Token  Testing Slides

Doctests

» Inline documentation

» <Copy from terminal to test file>

» Easy

Page 27: Token  Testing Slides

Awesome Documentation

def parse_ttag(token, required_tags): """ A function to parse a template tag.

It sets the name of the tag to 'tag_name' in the hash returned.

>>> from test_utils.templatetags.utils import parse_ttag >>> parse_ttag('super_cool_tag for my_object as obj', ['as']) {'tag_name': u'super_cool_tag', u'as': u'obj'} >>> parse_ttag('super_cool_tag for my_object as obj', ['as', 'for']) {'tag_name': u'super_cool_tag', u'as': u'obj', u'for': u'my_object'}

""" bits = token.split(' ') tags = {'tag_name': bits.pop(0)} for index, bit in enumerate(bits): bit = bit.strip() if bit in required_tags: if len(bits) != index-1: tags[bit] = bits[index+1] return tags

Page 28: Token  Testing Slides

Awesome Documentation

>>> from test_utils.templatetags.utils import parse_ttag >>> parse_ttag('super_cool_tag for my_object as obj', ['as']) {'tag_name': u'super_cool_tag', u'as': u'obj'} >>> parse_ttag('super_sweet for object as obj', ['as', 'for']) {'tag_name': u'super_sweet', u'as': u'obj', u'for': u'object'}

Page 29: Token  Testing Slides

Doctest problems

» Can’t use PDB

» Hide real failures

Page 30: Token  Testing Slides

Unit Tests

» Standard (XUnit)

» More robust

» setUp and tearDown

Page 31: Token  Testing Slides

Basic Unit Test

import randomimport unittest

class TestRandom(unittest.TestCase):

def setUp(self): self.seq = range(10)

def testshuffle(self): # shuffled sequence does not lose any elements random.shuffle(self.seq) self.seq.sort() self.assertEqual(self.seq, range(10))

if __name__ == '__main__': unittest.main()

Page 32: Token  Testing Slides

Django TestCase

» Subclasses unittest

» Fixtures

» Assertions

» Mail

» URLs

Page 33: Token  Testing Slides

Test Client

» Test HTTP Requests without server

» Test Views, Templates, and Context

Page 34: Token  Testing Slides

Django’s TestCase

from django.contrib.auth.models import Userfrom django.test import TestCasefrom django.core import mail

class PasswordResetTest(TestCase): fixtures = ['authtestdata.json'] urls = 'django.contrib.auth.urls'

def test_email_not_found(self): "Error is raised if the provided email address isn't currently registered" response = self.client.post('/password_reset/', {'email': '[email protected]'}) self.assertEquals(len(mail.outbox), 0)

Page 35: Token  Testing Slides

What flavor of test?

» Unit

» Functional

» Browser

Page 36: Token  Testing Slides

Unit test

» Low level tests

» Small, focused, exercising one bit of functionality

» Great for libraries

Page 37: Token  Testing Slides

Regression test

» Written when you find a bug

» Proves bug was fixed

» Django Tickets

Page 38: Token  Testing Slides

Functional

» ‘Black Box Testing’

» Check High Level Functionality

Page 39: Token  Testing Slides

Functional Testing Tools

» Twill

» Django Test Client

Page 40: Token  Testing Slides

Browser tests

» Run tests in a web browser

» Check compatibility of design

» Basically an IE sanity check

» Only real way to test JS, AJAX, CSS

» Slow

Page 41: Token  Testing Slides

Browser Testing Tools

» Windmill

» Selenium

Page 42: Token  Testing Slides
Page 43: Token  Testing Slides

Other kinds of testing

» Spiders

» Fuzz testing

» Load testing

Page 44: Token  Testing Slides

Where do I start?

Page 45: Token  Testing Slides

Use unittest unless you have a reason not to!

Page 46: Token  Testing Slides

Start with a regression test or a functional test

Page 47: Token  Testing Slides

Fixed a bug

Page 48: Token  Testing Slides

Poking at code on the command line

Page 49: Token  Testing Slides

Pony turned Horse

Page 50: Token  Testing Slides

Use the data, Luke

» Use data as a pivot

» Fixtures means you use Unit Tests

» Creation on the command line, Doctests

Page 51: Token  Testing Slides

Creating Fixtures

»./manage.py dumpdata <app>

»./manage.py makefixture Model[x:y]

»Follows relations

»Slicing

»By Hand

Page 52: Token  Testing Slides

Getting in Context

» ./manage.py testshell <fixture>

» (i)pdb

Page 53: Token  Testing Slides

Making Functional tests

» Usually a relatively annoying process

» Testmaker makes it easy.

» ./manage.py testmaker [app]

» Simply browse and your session is recorded.

Page 54: Token  Testing Slides

Testing your views gets you the most coverage.

Page 55: Token  Testing Slides

80% Case

Page 56: Token  Testing Slides

When > Where

Page 57: Token  Testing Slides

Enough to be useful

Page 58: Token  Testing Slides

Tools

Page 59: Token  Testing Slides

Summer of Code

» Test-Only Models

» Skipping tests

» Coverage

» Windmill tests of the admin

Page 60: Token  Testing Slides

Test-Only Models

» Allow for models available only during tests

» Don’t need test_project now!

Page 61: Token  Testing Slides

Test-Only Models

#test_models.py

from django.db import models

class TestModel(models.Model): name = models.CharField() #tests.py

from django.test import TestCase

class TestMyViews(TestCase): test_models = ['test_models']

def testIndexPageView(self): from myapp.models import TestModel TestModel.objects.get(name='daniellindsleyrocksdahouse')

Page 62: Token  Testing Slides

Skipping Tests

» Views Required

» Models Required

» Specific database type

» Conditional on a Function

Page 63: Token  Testing Slides

Skipping Tests

from django.tests.decorators import conditional_skipimport datetime

class TestUnderCondition(TestCase):

def _check_2009(): # Condition returning True if test should be run and False if it # should be skipped. if datetime.datetime.now() > datetime.datetime(2009, 01, 01): return True

@conditional_skip(_check_2009, reason='This test only runs in 2009') def testOnlyIn2009(self): # Test to run if _my_condition evaluates to True

Page 64: Token  Testing Slides

Skipping Tests

====================================================================== SKIPPED: test_email_found (django.contrib.auth.tests.basic.PasswordResetTest) ---------------------------------------------------------------------- Traceback (most recent call last): File "/Users/dnaquin/Dropbox/Sandbox/django/django/test/decorators.py", line 43, in _skip raise SkippedTest(reason=reason) SkippedTest: Required view for this test not found: django.contrib.auth.views.password_reset

---------------------------------------------------------------------- Ran 408 tests in 339.663s

FAILED (failures=1, skipped=2)

Page 65: Token  Testing Slides

Coverage

» Basically the hotness

» django-admin.py test --coverage

» django-admin.py test --coverage --report

Page 66: Token  Testing Slides

Basic Coverage

Page 67: Token  Testing Slides

Pretty Coverage

Page 68: Token  Testing Slides

Pretty Coverage

Page 69: Token  Testing Slides

Windmill Tests

» Didn’t get finished

» Allow for functional tests of the admin

» Allow for custom Windmill tests of your apps

Page 70: Token  Testing Slides

Custom Test Runners

» Allow you to do anything you want

» Load custom fixtures

» nose or py.test runners

Page 71: Token  Testing Slides

Django Test Extensions

» Gareth Rushgrove

» Extra Assertions

» Coverage and XML Test Runners

» http://github.com/garethr/django-test-extensions

Page 72: Token  Testing Slides

Django Sane Testing

» Ella Folks

» Based on nosetests

» Selenium

» Live server

» http://devel.almad.net/trac/django-sane-testing/

Page 74: Token  Testing Slides

Goals

Page 75: Token  Testing Slides

Some form of TDD

» Write tests as you write code

» Makes your code easy to test

Page 76: Token  Testing Slides

Follow Django’s Model

» Tests with every commit

» Docs with every commit

» Run tests before commiting

Page 77: Token  Testing Slides

Continuous Integration

Page 78: Token  Testing Slides

NEVER LEAVE THE BUILD BROKEN

Page 79: Token  Testing Slides

Love Green

Page 80: Token  Testing Slides

Profiling

» python -m cProfile manage.py test

» Allows you to profile a repeatable case

» Faster tests = Faster production

Page 81: Token  Testing Slides

Things to remember

Page 82: Token  Testing Slides

Testing is not hard, you just have to get started.

Page 83: Token  Testing Slides

If your code doesn’t have tests, it will be hard/impossible to

refactor

Page 84: Token  Testing Slides

Once you have tests, you need to run them!

Page 85: Token  Testing Slides

Teh Pretty

» Thanks to Idan Gazit for design help

Page 87: Token  Testing Slides

Questions?

» twitter.com/ericholscher

» http://ericholscher.com

» [email protected]