testing django applications

25
Testing Django Applications Honza Král Follow me: @honzakral E-mail me: [email protected]

Upload: honza-kral

Post on 14-Jan-2015

2.167 views

Category:

Technology


0 download

DESCRIPTION

Talk given at euro djangocon 2010

TRANSCRIPT

Page 1: Testing Django Applications

Testing Django Applications

Honza Král

Follow me: @honzakralE-mail me: [email protected]

Page 2: Testing Django Applications

Why Test?

Page 3: Testing Django Applications

You already do!

Whenever you● open your browser to look at the result● run some part of your code in a console● look into the database directly

Is it fun?

Page 4: Testing Django Applications

Be lazy!

Let the computer do the boring work.

Page 5: Testing Django Applications

Even if you are perfect programmers (which you are not)

Tests will make you fearless of:● deployment (will this work?)● refactoring (what will this break?)● new developers (can I trust them?)● regressions (didn't I fix this before?)

Why assume it's OK when you can test?

Page 6: Testing Django Applications

Terminology

● Unit tests● Integration tests● Acceptance tests● Performance tests● Load tests● Stress tests● UX tests● .........

Page 7: Testing Django Applications

Unit testsfrom unittest import TestCase

class TestInterview(TestCase):def setUp(self):

self.interview = Interview( ... )

def test_ask_indicators_when_active(self): self.assertEquals(

True, self.interview.asking_started()) self.assertEquals(

False, self.interview.asking_ended())self.assertEquals(

True, self.interview.can_ask())

Page 8: Testing Django Applications

Unit tests

● No interaction with other components● Including DB

● Fast● Tied to the code● Testing small portion of the code

Page 9: Testing Django Applications

Integration testsfrom django.test import TestCase

class TestInterview(TestCase):def setUp(self):

self.interview = Interview.objects.create(...)

def test_unanswered_questions(self):q = Question.objects.create(

interview=self.interview,content='What ?')

self.assertEquals([q],self.interview.unanswered_questions())

Page 10: Testing Django Applications

Integration tests

● Test how components cooperate together● Most common tests in Django apps● Usually slower and cover more code● Important to have

Page 11: Testing Django Applications

Testability

Page 12: Testing Django Applications

(unit) testability

● avoid side effects● separate components● only accept parameters you need

● request is bad

● be smart about transactions and models● don't put busines logic into views (use models)

Page 13: Testing Django Applications

Separate components (views)def my_view(request, some_id, action, ...):

main_model = get_object_or_404(M, pk=some_id)other = main_model.method(action)... compute ... some ... data... return render_to_response(...)

● To test this you need to:● define the template● mock request or use test client● access the database● ...

Page 14: Testing Django Applications

Class-based views FTW!class MyView(object):

def get_objects(self, some_id, action): ...

def render_response(self, context): ...

def compute_data(self, m1, m2): ...

def __call__(self, request, some_id, action, ...):m1, m2 = self.get_objects(some_id, action)context = self.compute_data(m1, m2)return self.render_response(context)

● now you can easily test individual methods● or just the interesting ones (compute_data)

Page 15: Testing Django Applications

Separate components (template tags)

def test_parse_fails_on_too_few_arguments(self):self.assertRaises(

TemplateSyntaxError, _parse_box,['box', 'box_type', 'for'])

def test_parse_box_with_pk(self):node = _parse_box(['box', 'box_type', 'for',

'core.category', 'with', 'pk', '1'])

self.assertTrue(isinstance(node, BoxNode))self.assertEquals('box_type', node.box_type)self.assertEquals(Category, node.model)self.assertEquals(('pk', '1'), node.lookup)

Page 16: Testing Django Applications

Testing templatetags

from unittest import TestCase

class TestRenderTag(TestCase):def setUp(self):

self.template = template.Template('{% load myapp %}{% render var %}')

def test_does_not_escape_output(self):c = template.Context({'var': '<html> ""'})self.assertEquals(

'<html> ""', self.template.render(c))

Page 17: Testing Django Applications

Testing models

Try to avoid DB

def test_taller_img_gets_cropped_to_ratio(self):format = Format(

max_height=100, max_width=100)i = Image.new('RGB', (100, 200), "black")f = Formatter(i, format)

i, crop_box = f.format()self.assertEquals(

(0, 50, 100, 150), crop_box)self.assertEquals((100, 100), i.size)

Page 18: Testing Django Applications

Populating test DB

● fixtures only work for static data● natural keys FTW!● use factories when fixtures aren't enoughdef get_payment_assesment(stay, ** kwargs):

defaults = {'modified_by':

User.objects.get_or_create(...),'stay': stay,...}

defaults.update(kwargs)return PaymentAssesment.objects.create(

**defaults)

Page 19: Testing Django Applications

Testing forms

from unittest import TestCase

class TestPaymentAssesmentFormSet(TestCase):def setUp(self):

self.data = {…}

def test_formset_validates_valid_data(self):fset = PaymentAssesmentFormSet(self.data)self.assertTrue(fset.is_valid())

def test_fail_for_change_inside_a_month(self):self.data['form-0-valid_to'] = '1.06.2009'self.data['form-1-valid_from'] = '2.06.2009'fset = PaymentAssesmentFormSet(self.data)self.assertFalse(fset.is_valid())

Page 20: Testing Django Applications

Tests alone are not enough!

Page 21: Testing Django Applications

Infrastructure

● simple and convenient way to run tests● fast tests (or way to run just part of the suite)● never let your test suite break● continuous integration

● reporting● leaving this to the experts

(assuming they catch their flight)

Page 22: Testing Django Applications

Other requirements

● when test fails you must know what went wrong● no doctests● descriptive test names● short tests touching minimal amount of code

● write even trivial tests as a starting point● make sure tests work

Page 23: Testing Django Applications

Happy hour

If you have done your tests right, you will get extras:● convenient way to bootstrap your application● no need for server/browser during development● calmer nerves● people will trust your work!

Page 24: Testing Django Applications

?

Page 25: Testing Django Applications

Thanks for listening

Honza Král

Follow me: @honzakralE-mail me: [email protected]