Django Testing

  • View
    11.627

  • Download
    1

  • Category

    Business

Preview:

DESCRIPTION

Talk about where Testing is in Django, and how to get started doing it.

Citation preview

Django TestingEric Holscher

http://ericholscher.com

Django Testing

1Tuesday, May 5, 2009

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.

2Tuesday, May 5, 2009

30,000 Ft View

• State of testing in Django

• Why you should be testing

• How you start testing

• Useful tools

• Eventual Goals

3Tuesday, May 5, 2009

State of Django Testing

4Tuesday, May 5, 2009

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

5Tuesday, May 5, 2009

Django 1.1

Making Testing Possible since 2009

6Tuesday, May 5, 2009

manage.py startapp creates a tests.py

7Tuesday, May 5, 2009

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"""}

8Tuesday, May 5, 2009

Fast Tests(Transactions)

9Tuesday, May 5, 2009

0

15

30

45

60

Django 1.0 Django 1.1

Ellington Test Speedup

Minutes (Lower is better)

10Tuesday, May 5, 2009

You now have no excuse.

11Tuesday, May 5, 2009

Why to test

12Tuesday, May 5, 2009

Scary13Tuesday, May 5, 2009

Less Scary14Tuesday, May 5, 2009

Not Scary15Tuesday, May 5, 2009

Peace of Mind16Tuesday, May 5, 2009

Code must adapt

17Tuesday, May 5, 2009

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

one most responsive to change.”

- Charles Darwin

18Tuesday, May 5, 2009

Won’t somebody please think of the users?!

19Tuesday, May 5, 2009

Tests as Documentation

20Tuesday, May 5, 2009

Tests as Documentation

Test driven development +

Document driven development=

Test Driven Documentation

20Tuesday, May 5, 2009

“Code without tests is broken as designed”- Jacob Kaplan-Moss

21Tuesday, May 5, 2009

Dizzying Array of Testing Options

22Tuesday, May 5, 2009

What kind of test?

• doctest

• unittest

23Tuesday, May 5, 2009

Doctests

• Inline documentation

• <Copy from terminal to test file>

• Can’t use PDB

• Hide real failures

• “Easy”

24Tuesday, May 5, 2009

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

25Tuesday, May 5, 2009

Unit Tests

• Use for everything else

• More rubust

• setUp and tearDown

• Standard (XUnit)

26Tuesday, May 5, 2009

import randomimport unittest

class TestRandom(unittest.TestCase):

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

def testshuffle(self): # make sure the 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()

27Tuesday, May 5, 2009

Django TestCase

• Subclasses unittest

• Fixtures

• Assertions

• Mail

• URLs

28Tuesday, May 5, 2009

Test Client

• Test HTTP Requests without server

• Test Views, Templates, and Context

29Tuesday, May 5, 2009

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.get('/password_reset/') self.assertEquals(response.status_code, 200) response = self.client.post('/password_reset/', {'email': 'not_a_real_email@email.com'}) self.assertContains(response, "That e-mail address doesn&#39;t have an associated user account") self.assertEquals(len(mail.outbox), 0)

30Tuesday, May 5, 2009

What flavor of test?

• Unit

• Functional

• Browser

31Tuesday, May 5, 2009

Unit test

• Low level tests

• Small, focused, exercising one bit of functionality

32Tuesday, May 5, 2009

Regression test

• Written when you find a bug

• Proves bug was fixed

• Django Tickets

33Tuesday, May 5, 2009

Functional

• “Black Box Testing”

• Check High Level Functionality

34Tuesday, May 5, 2009

Functional Testing Tools

• Twill

• Django Test Client

• ...

35Tuesday, May 5, 2009

Ellington

• Lots of different clients

• Need to test deployment (Functional)

36Tuesday, May 5, 2009

go {{ site.url }}/marketplace/search/formvalue 1 q pizzasubmitcode 200

37Tuesday, May 5, 2009

38Tuesday, May 5, 2009

Pretty Functional Tests39Tuesday, May 5, 2009

Can test

• All sites on a server

• All sites of a certain type

• A single problemed client

• A test across all sites

40Tuesday, May 5, 2009

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

41Tuesday, May 5, 2009

Browser Testing Tools

• Windmill

• Selenium

42Tuesday, May 5, 2009

43Tuesday, May 5, 2009

Other kinds of testing

• Spiders

• Fuzz testing

• Load testing

• Prayer

44Tuesday, May 5, 2009

Where do I start?

45Tuesday, May 5, 2009

Fixed a bug

46Tuesday, May 5, 2009

Poking at code on the command line

47Tuesday, May 5, 2009

Pony turned Horse

48Tuesday, May 5, 2009

Now what?

49Tuesday, May 5, 2009

Start with a regression test or a functional test

50Tuesday, May 5, 2009

Use unittest unless you have a reason not to!

51Tuesday, May 5, 2009

Use the data, Luke

• Use data as a pivot

• Fixtures means you use Unit Tests

• Creation on the command line, Doctests

52Tuesday, May 5, 2009

Creating Fixtures

• ./manage.py dumpdata <app>

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

• Follows relations

• By Hand

53Tuesday, May 5, 2009

TestShell

./manage.py testshell <fixture>

54Tuesday, May 5, 2009

Making Functional tests

• Usually a relatively annoying process

• Testmaker makes it easy.

• ./manage.py testmaker <app>

• Simply browse and your session is recorded.

55Tuesday, May 5, 2009

Testing your views generally gets you the

most coverage.

56Tuesday, May 5, 2009

80% Case

57Tuesday, May 5, 2009

When > Where

58Tuesday, May 5, 2009

Tools

59Tuesday, May 5, 2009

Coverage

60Tuesday, May 5, 2009

61Tuesday, May 5, 2009

Mock Objects

• http://www.voidspace.org.uk/python/mock/

62Tuesday, May 5, 2009

import unittestfrom mock import Mock from templatetags.cms_tags import if_link_is_active, IsActiveNode class TestIsActiveTag(unittest.TestCase): def test_returns_correct_node_type(self): token = Mock(methods=['split_contents']) token.split_contents.return_value = ('if_link_is_active', 'bar') self.assertEqual(type(if_link_is_active(Mock(), token)), IsActiveNode)

63Tuesday, May 5, 2009

Custom Test Runners

64Tuesday, May 5, 2009

Django Test Extensions

• Gareth Rushgrove

• Extra Assertions

• Coverage and XML Test Runners

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

65Tuesday, May 5, 2009

Django Sane Testing

• Ella Folk, Lucas (Hi!)

• Based on nosetests

• Selenium

• Live server

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

66Tuesday, May 5, 2009

Django Test Utils

• Mine!

• Testmaker

• Crawler

• Random fanciness

• http://github.com/ericholscher/django-test-utils/tree/master

67Tuesday, May 5, 2009

Recording tests is generally seen as bad.

68Tuesday, May 5, 2009

My philosophy

• Write tests.

• Notice patterns and best practices

• Automate recording of tests with those patterns

• If you can’t automate, use tools to make it easier.

69Tuesday, May 5, 2009

Process for testmaker

• Most view tests check status_code and response context

• Write middleware that catches this info

• Records it to a file

• Err on the side of more data.

70Tuesday, May 5, 2009

Goals(That perfect world)

71Tuesday, May 5, 2009

Some form of TDD

• Write tests as you write code

• Makes your code easy to test

72Tuesday, May 5, 2009

Follow Django’s Model

• Tests with every commit

• Docs with every commit

• Run tests before commiting

73Tuesday, May 5, 2009

Use a DVCS

• At work we have a central SVN repo

• Git feature branches

• Code is staged for documentation and testing

• Committed to SVN once it is “done”

74Tuesday, May 5, 2009

Continuous Integration

75Tuesday, May 5, 2009

NEVER LEAVE THE BUILD BROKEN

76Tuesday, May 5, 2009

Love Green77Tuesday, May 5, 2009

Fast(er) Tests

78Tuesday, May 5, 2009

JSON

79Tuesday, May 5, 2009

Profiling

python -m cProfile manage.py test

80Tuesday, May 5, 2009

Mock Objects

http://www.voidspace.org.uk/python/mock/

81Tuesday, May 5, 2009

Future and Ponies

82Tuesday, May 5, 2009

Summer of Code

• Test-Only Models

• Coverage

• Windmill tests of the admin

83Tuesday, May 5, 2009

Test Suites in Django

84Tuesday, May 5, 2009

Central Testing Repository

85Tuesday, May 5, 2009

Nose Plugin Integration

86Tuesday, May 5, 2009

Things to remember

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

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

• Once you have tests, you need to run them!

87Tuesday, May 5, 2009

Recommended