Python: Automated Testing with Grunt (Node.js)

I've been frustrated with the available Python testing frameworks lately, after playing around with Ruby and Node.js I just cant get enough of automated testing and coloured output.  Out of the box there is no way to do this in Python, and the available modules just aren't there yet.

But there is a way around it, which utilized a Node module called Grunt.  When combined with Nosetests and Rednose you have an excellent little automated testing system, with colourized output. Why colourized output in Python Testing is such an afterthough, when it is prevelent in every other language is mind boggling, so much for "batteries included."

The first thing your going to need to do, besides having your Python environment set up is to install Node.js.  Use your favourite package manager, or visit the Node.js website to install.

To start, lets create a project to test in.

  • mkdir myapp
  • touch myapp/__init__.py
  • mkdir myapp/tests
  • touch myapp/base.py
  • touch myapp/tests/test_stuff.py
  • cd myapp
  • virtualenv ENV --no-site-packages
  • source ENV/bin/activate

Now that we have the basic layout for testing this set up in place, and activated our environment we install the python and node packages we need.

  • pip install nose rednose
  • npm install -g grunt #The -g is important for this module, it installs it globally so you can use the executable command grunt
  • npm install grunt-nose
  • npm install grunt-contrib-watch

You should now have a node_modules folder under myapp, its time to create your grunt config file "Gruntfile.js"

module.exports = function(grunt) {
  grunt.initConfig({
   nose: {
     options: {
      verbosity: 2, 
      rednose: true
     },
     src: ['./'] 
    },

    watch: {
      js: {
        options: {
          spawn: true,
          interrupt: true,
          debounceDelay: 250,
        },
        files: ['Gruntfile.js', '*.py', '**/*.py'],
        tasks: ['nose']
     }
    }
  });

  grunt.loadNpmTasks('grunt-nose');
  grunt.loadNpmTasks('grunt-contrib-watch');

  grunt.registerTask('default', ['nose'])

};

Here we are defining two tasks, one to run nose and a watcher to execute nose when it detects changes.  It will also reload grunt if we make changes to the Gruntfile.

At this point we can start our watcher.

  • grunt watch

Leave that running and open up a different terminal window next to it.  The next thing we will do is write a couple of tests.

 from myapp import base
import unittest

class TestSomething(unittest.TestCase):
    
    def test_base(self):
        """Just want a passing test"""
        self.assertTrue(base.passing())

    def test_base_fail(self):
        """A failing test"""
        self.assertTrue(base.failing())

As soon as you save these changes you should see the tests run in your other terminal, provided you left the watcher running.  Both tests will fail of course because we havent created our base module yet.

 
def passing():
    return True                                                                              
                                                                                             
def failing():                                                                               
    return False  

If everything is working the way it should, the terminal running grunt watch will be showing one passing and one failing test.  Thats all there is to it, write more tests and play around.  

I am loving this.