Using Sublime Text Build System for Project Unit Tests

I spent some time today learning about the Build System. In addition to the built-in build systems for various languages, and the possibility of defining custom build systems at the user preference level, you can also specify project build systems.

I added the following stanza to one of my .sublime-project files:

         "name": "unittest-discover",
         "shell_cmd": "~/.virtualenvs/randopony-tetra-2.7/bin/python
                       -m unittest discover ${project_path}"

to enable me to run the test suite for the project within Sublime at the touch of a key.

Things to note:

  • The name element defines how the build will appear in the Tools > Build System menu.
  • In the shell_cmd element:
    • I use an explicit path to the python interpreter in the project's virtualenv so that the project's dependencies are found correctly.
    • The shell that the Sublime build command launches will have as its cwd the directory that the file you initiate the build command from is in. ${project_path} is a build system variable that points to the directory where the .sublime-project file is, and I use that to tell unittest discover where to start searching for tests.
  • You can define as many build systems as you want in the .sublime-project file, just be sure to give them different names.

After reloading the .sublime-project file, choose unittest-discover from the Tools > Build System menu, and launch a build (⌘B on OS/X), and voilà, the test suite runs in a pane that pops up at the bottom of the Sublime window.

Read and Post Comments

YAML Fixtures in Django Tests

I have a Django project called RandoPony that handles event registration for the BC Randonneurs Cycling Club. It's on an annual release cycle; i.e. I spend the few weeks that pass for winter in Vancouver updating the project. That's when I bump it to the latest version of Django, fixing minor bugs, and adding new features that I and other users have come up with during the preceding year. Once I release a new version for the new year, I usually don't have to worry about the code until the next winter. The pony just works, facilitating people doing hundreds of thousands of kilometres of crazy long cycling events, and we like it that way!

My workflow at the beginning of the annual update looks something like:

  • Create a new virtualenv
  • Install the latest version of Django and other project dependencies
  • Read the release notes for the Django releases since the one I was working with last
  • Run the RandoPony test suite to find deprecations and other obvious breakage
  • Start hacking

I recently started working on the 2012 release of RandoPony and was blown away when I ran the test suite because there were over 60 failing tests! It took me way longer than it should have to figure out why things were so massively broken.

The problem was that the test fixtures weren't being installed. They weren't being installed because they are YAML files and I had forgotten to install PyYAML in the virtualenv. What's really annoying is that the fixtures files were being ignored silently.

It turns out that if you specify a YAML fixture for a Django TestCase:

class TestPopulairesListView(django.test.TestCase):
    """Functional tests for populaires-list view.
    fixtures = ['populaires']

without giving the fixture file a .yaml extension, the fixture will be silently ignored if PyYAML isn't installed. Really, Django?!

So, the number 1 thing that I should have done to save myself from this thrash was to explicitly specify the serialization format of my fixtures:

class TestPopulairesListView(django.test.TestCase):
    """Functional tests for populaires-list view.
    fixtures = ['populaires.yaml']

Then the Django test runner would have told me:

Problem installing fixture 'populaires': yaml is not a known
serialization format.

I'll take the hit for ignoring the PEP 20 aphorism "Explicit is better than implicit". But shouldn't Django get docked for "Errors should never pass silently"?

The other thing I should have done was use a pip requirements file for the project.

RandoPony has 2 requirements files now. requirements.txt for the packages required for the production deployment, and requirements-dev.txt for the additional packages, like PyYAML, required for development work. Now I just have to hope that I'm smart enough when I start work on the 2013 release to do:

(randopony)$ pip install -r requirements.txt
(randopony)$ pip install -r requirements-dev.txt
Read and Post Comments