Created
November 1, 2012 20:56
-
-
Save ethanwhite/3996485 to your computer and use it in GitHub Desktop.
Testing in an IPython Notebook
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"metadata": { | |
"name": "testing_in_ipynb" | |
}, | |
"nbformat": 3, | |
"nbformat_minor": 0, | |
"worksheets": [ | |
{ | |
"cells": [ | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"Testing inside an IPython Notebook\n", | |
"===================================\n", | |
"\n", | |
"In my courses and as part of [Software Carpentry](http://software-carpentry.org)\n", | |
"I'm teaching more and more in IPython notebooks. One of the things I/we teach\n", | |
"is testing, so I wondered if I could teach it in a notebook as well. With quite\n", | |
"a lot of help from [Matthias Bussonnier](https://twitter.com/Mbussonn) I got it\n", | |
"working so I thought I'd share." | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"An example\n", | |
"----------------\n", | |
"\n", | |
"We will test a function that caluculates the GC-content of a DNA sequence.\n", | |
"The GC-content is simply the percentage of bases in the DNA sequence that\n", | |
"are either G's or C's. So, for example, the GC-content of 'ATTGC' is 40%.\n", | |
"\n", | |
"The function we are testing is ``get_gc_content()`` and it takes a single\n", | |
"argument, which is a string represting a sequence. This function is in\n", | |
"a custom module called ``dna_analysis.py``.\n", | |
"\n", | |
"### Create the module to test\n", | |
"We can use the ``%%file`` magic to save a block of code to a file, so we\n", | |
"can use that to create the module that we're going to test." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"%%file dna_analysis.py\n", | |
"\n", | |
"\"\"\"Code for analyzing DNA sequences\"\"\"\n", | |
"\n", | |
"from __future__ import division\n", | |
"\n", | |
"def get_gc_content(seq):\n", | |
" \"\"\"Determine the GC content of a sequence\"\"\"\n", | |
" seq = seq.upper()\n", | |
" gc_content = 100 * (seq.count('G') + seq.count('C')) / len(seq)\n", | |
" return gc_content" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"stream": "stdout", | |
"text": [ | |
"Writing dna_analysis.py\n" | |
] | |
} | |
], | |
"prompt_number": 1 | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"### Create the test module\n", | |
"1. To use nosetests we need to save the test code to a Python file starting with the word *test*\n", | |
"2. We then need to import the function(s) we are going to test\n", | |
"3. Then we right a simple function (whose name starts with *test*) that calls the function and\n", | |
"checks to see if it returns the right value" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"%%file test_dna.py\n", | |
"\n", | |
"from dna_analysis import get_gc_content\n", | |
"\n", | |
"def test_get_gc_content_zero():\n", | |
" assert get_gc_content('ATTATTAAA') == 0\n", | |
" \n", | |
"def test_get_gc_content_lowercase():\n", | |
" assert get_gc_content('atgcatgc') == 50\n", | |
" \n", | |
"def test_get_gc_content_multiline():\n", | |
" sequence = \"\"\"atta\n", | |
"gccg\n", | |
"attt\n", | |
"cccg\"\"\"\n", | |
" assert get_gc_content(sequence) == 50" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"stream": "stdout", | |
"text": [ | |
"Writing test_dna.py\n" | |
] | |
} | |
], | |
"prompt_number": 2 | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"### Run nosetests\n", | |
"We would normally run nosetests from the command line, so in IPython we can just call ``!nosetests``." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"!nosetests" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"stream": "stdout", | |
"text": [ | |
"..F\r\n", | |
"======================================================================\r\n", | |
"FAIL: test_dna.test_get_gc_content_multiline\r\n", | |
"----------------------------------------------------------------------\r\n", | |
"Traceback (most recent call last):\r\n", | |
" File \"/usr/lib/python2.7/dist-packages/nose/case.py\", line 197, in runTest\r\n", | |
" self.test(*self.arg)\r\n", | |
" File \"/home/ethan/Dropbox/Teaching/ProgBiol/repo/ipynbs/test_dna.py\", line 15, in test_get_gc_content_multiline\r\n", | |
" assert get_gc_content(sequence) == 50\r\n", | |
"AssertionError\r\n", | |
"\r\n", | |
"----------------------------------------------------------------------\r\n", | |
"Ran 3 tests in 0.018s\r\n", | |
"\r\n", | |
"FAILED (failures=1)\r\n" | |
] | |
} | |
], | |
"prompt_number": 3 | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"This is exactly we output we want since the original function handles most basic cases,\n", | |
"but not multiline strings." | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"Value?\n", | |
"------\n", | |
"I wonder a bit about how valuable this is in the sense that we probably wouldn't\n", | |
"normally run tests this way (at least I don't at the moment). But, I think at\n", | |
"least for a short workshop where we're teaching all of the Python in a notebook\n", | |
"that the value of reducing the cognitive load relative to switching environments\n", | |
"for the testing portion might outweigh doing something in a way that might not be exactly\n", | |
"how we would do it in day to day work." | |
] | |
} | |
], | |
"metadata": {} | |
} | |
] | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment