William Liu

Testing


##Table of Contents

##Summary

Testing your code is important because it creates scaffolding for large projects. When you build new features, you also ensure that you don’t destroy something else accidentally. There’s a lot of different libraries including:

Tests can be broken down into the following:

Some good rules to follow by:

####Functional Tests

Functional tests (aka Acceptance Test, End-To-End Test, Black Box Test) tests many methods and may interact with dependencies like databases or web services. You don’t look at the code, but test as if you were a user (instead of the programmer). Examples include running selenium to simulate opening a browser, clicking on things. A few simple functional test might pop up a Firefox browser and check the browser title:

from selenium import webdriver

browser = webdriver.Firefox()
browser.get('http://localhost:8080')

assert 'Django' in browser.title

Functional tests should be driving the development. We make a failing functional test first. Then we add unit tests. Then we add code that fixes the unit tests, that then ultimately fix the functional tests.

Normally functional tests are stored outside of a Django app because users don’t know how the apps are structured. Users just want to see that the entire website works as a whole.

You can write your own unittest.TestCase for your functional tests, but you’re basically building from the ground up with things like setUp and tearDown. Instead, you should use django.test import LiveServerTestCase where most of that functionality is done (e.g. you don’t have to hardcode the localhost port 8000 and can instead use )

####Unit Tests

Unit tests ensure that a small part of your code works in isolation. Each of these should be able to run alone and within a test suite regardless of the order called. This can mean that each test loads a fresh set of fields using setUp() and tearDown() methods. Dependencies are all mocked up. These tests should be fast and small. If they’re not small, break it up to smaller pieces. The idea is that you are looking at this program from the perspective of the programmer (and not the user). To run this test, you normally do a manage.py test where files like tests.py would sit inside your apps.

####Integration Tests

So how does this work? We write a function test that fails, then we write a unit test that fails. We then write some code to pass the unit test. Then we check that the functional test is working. If it doesn’t, we write some more unit tests/code until the functional test passes.

We can use integration tests to ensure that all the above tests work well together.

##Run Tests

Execute tests using the following commands:

##Loading Data

You can load data (into and out of databases, into test files, etc) a few different ways. These include using fixtures and mocks.

##Fixtures

To create a state for your database, we can create fixtures.

####Dumping DB Data into Fixtures

In Django, if your app has data in the database, you can create fixtures by using the dumpdata command:

python manage.py dumpdata myapp --format=yaml > myapp/fixtures/db_data.yaml

This fixture is really just a serialization of your database data into a yaml file. By default the fixture is in JSON format. You can edit this feature in the text editor if you’d like.

####Loading Data from Fixtures

If you want to load your data (into the db or the command line) from your Fixtures, we call this deserialization. You can do this with:

from django.core.management import call_command
call_command("loaddata", "' + db_data.yaml' + '", verbosity=8)

This is the same as (except this is from the command line):

python manage.py loaddata db_data.yaml

####Using Fixtures in Unit Tests

from django.test import TestCase
from myapp.models import Stuff

class StuffTests(TestCase):
    # Note: this is the fixture
    # model: myapp.stuff
    # pk: 1
    # fields: {content: lots of stuff, query: test, title: test, url: 'test'}
    fixtures = ['mine']

    def testFlufflyAnimals(self):
        s = Stuff.objects.get(pk=1)
        self.assertEquals(s.query, 'test')
        s.query = 'who cares'
        s.save()

For more on testing the serializer and deserializer: http://django-testing-docs.readthedocs.org/en/latest/serialization.html

More specifically, you can use the DRF’s APIRequestFactory for testing serializers and deserializers.

##Doubles

When you’re testing individual units, you’ll realize that some parts rely on others. This is where we get into test doubles, which are kinda like stunt doubles in movies. While this isn’t a real name, we can define what kind of test objects we have, which can include:

An example between stubs and mocks would be if we tested sending out an email. Stubs would send out the fake email and verify it was sent. Mocks would take it a step further and also check if we sent it to the right person, with the right contents, etc.

##Mocking

By mocking objects, you can simulate objects and mimic the behavior of real objects in a controlled way. For example, you would create a mock object to test the behavior of some other object. Some reasons for mocking an object include:

An example is if we mock an alarm clock going off at 7:00am, we wouldn’t want to wait till 7:00am just to test. Another example is if we post to facebook, we don’t want to actually have to post to facebook.