Testing

Note

The below examples are in Python, but the concepts apply to testing in any language.

See also

Looking for OSF-specific testing guidelines? See the Testing the OSF page.

General Testing Guidelines

  • Use long, descriptive names. This often obviates the need for doctrings in test methods. This also makes it easier to locate tests that fail.
  • Tests should be isolated. Don’t interact with a real database or network. Use a separate test database that gets torn down or use mock objects.
  • Prefer factories to fixtures.
  • Never let incomplete tests pass, else you run the risk of forgetting about them. Instead, add a placeholder like assert False, "TODO: finish me". If you are stubbing out a test that will be written in the future, use the @unittest.skip() decorator.
  • Strive for 100% code coverage, but don’t get obsess over coverage scores.
  • When testing the contents of a dictionary, test the keys individually.
# Yes
assert_equal(result['foo'], 42)
assert_equal(result['bar'], 24)

# No
assert_equal(result, {'foo': 42, 'bar': 24})

Unit Tests

  • Focus on one tiny bit of functionality.
  • Should be fast, but a slow test is better than no test.
  • It often makes sense to have one testcase class for a single class or model.
import unittest
import factories

class PersonTest(unittest.TestCase):
    def setUp(self):
        self.person = factories.PersonFactory()

    def test_has_age_in_dog_years(self):
         assert self.person.dog_years == self.person.age / 7

Functional Tests

Functional tests are higher level tests that are closer to how an end-user would interact with your application. They are typically used for web and GUI applications.

  • Write tests as scenarios. Testcase and test method names should read like a scenario description.
  • Use comments to write out stories, before writing the test code.
class TestAUser(unittest.TestCase):
    def test_can_write_a_blog_post(self):
        # Goes to the her dashboard
        ...
        # Clicks "New Post"
        ...
        # Fills out the post form
        ...
        # Clicks "Submit"
        ...
        # Can see the new post
        ...

Notice how the testcase and test method read together like “Test A User can write a blog post”.

Supporting Libraries

Python

  • nose: Extends Python’s unittest. Includes a test runner and various utilities.
  • pytest: A powerful test runner and library for writing automated tests.
  • factory-boy: Utility library for creating test objects. Replaces fixtures with “factories”.
  • mock: Allows you to mock and patch objects for testing purposes.
  • webtest / webtest-plus : Provides a TestApp with which to send test requests and make assertions about the responses.
  • faker : A fake data generator.

Javascript

  • Karma: Test runner.
  • Mocha: Test framework/interface.
  • Chai: Assertion library.
  • Sinon: Test spies and mocks.