"* Testing\n",
"* Nose\n",
"* Test-driven development\n",
- "* Exceptions"
+ "* Exceptions\n",
+ "* Practice"
]
},
{
"***"
]
},
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "***\n",
+ "# Practice\n",
+ "***\n",
+ "\n",
+ "## Filtering animals\n",
+ "\n",
+ "We have a function to read animals from a file and return lists containing the columns, and we have a function that calculates a mean for a list of numbers. What else do we need?"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Exercise: Write the `filter_animals` function and its tests\n",
+ "\n",
+ "This function should:\n",
+ "\n",
+ "* Accept the name of the animal we are interested in catching in the filter\n",
+ "* Accept four lists containing unfiltered dates, times, animal names, and counts\n",
+ "* Return four lists containing dates, times, animal names, and counts, pertaining only to the animal that we wanted to catch in the filter\n",
+ "* Be tested!"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Results\n",
+ "\n",
+ "When you are done, your code should look something like this."
+ ]
+ },
{
"cell_type": "code",
"collapsed": false,
"input": [
- "def filter_animals(species, date, time, animal, count):\n",
- " \"\"\"\n",
- " Given a particular species, filter out the data for just that species.\n",
- "\n",
- " Returns four lists: date, time, animal, count.\n",
- " \"\"\"\n",
- " fdate = []\n",
- " ftime = []\n",
- " fanimal = []\n",
- " fcount = []\n",
+ "def filter_animals(filtered_animal, dates, times, animals, counts):\n",
+ " '''Given a particular species, filter out and return just the data for that species.'''\n",
+ "\n",
+ " filtered_dates = []\n",
+ " filtered_times = []\n",
+ " filtered_animals = []\n",
+ " filtered_counts = []\n",
" \n",
- " for d, t, a, c in zip(date, time, animal, count):\n",
- " if a == species:\n",
- " fdate.append(d)\n",
- " ftime.append(t)\n",
- " fanimal.append(a)\n",
- " fcount.append(c)\n",
+ " for date, time, animal, count in zip(dates, times, animals, counts):\n",
+ " if animal == filtered_animal:\n",
+ " filtered_dates.append(date)\n",
+ " filtered_times.append(time)\n",
+ " filtered_animals.append(animal)\n",
+ " filtered_counts.append(count)\n",
" \n",
- " return fdate, ftime, fanimal, fcount"
+ " return filtered_dates, filtered_times, filtered_animals, filtered_counts"
],
"language": "python",
"metadata": {},
"outputs": [],
- "prompt_number": 36
+ "prompt_number": 48
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Does it work?"
+ ]
},
{
"cell_type": "code",
]
}
],
- "prompt_number": 33
+ "prompt_number": 49
},
{
"cell_type": "code",
"collapsed": false,
"input": [
- "def test_filter_animals1():\n",
- " date, time, animal, count = read_file('animals.txt')\n",
- " fdate, ftime, fanimal, fcount = filter_animals('Elk', date, time, animal, count)\n",
+ "dates, times, animals, counts = read_sightings_from_file('animals.txt')\n",
+ "print filter_animals('Elk', dates, times, animals, counts)"
+ ],
+ "language": "python",
+ "metadata": {},
+ "outputs": [
+ {
+ "output_type": "stream",
+ "stream": "stdout",
+ "text": [
+ "(['2011-04-23', '2011-04-23'], ['14:12', '10:24'], ['Elk', 'Elk'], [25, 26])"
+ ]
+ },
+ {
+ "output_type": "stream",
+ "stream": "stdout",
+ "text": [
+ "\n"
+ ]
+ }
+ ],
+ "prompt_number": 50
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "What do your tests look like?"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "collapsed": false,
+ "input": [
+ "def test_filter_finds_one_animal_in_list():\n",
+ " sample_dates = ['2011-04-23']\n",
+ " sample_times = ['14:12']\n",
+ " sample_animals = ['Elk']\n",
+ " sample_counts = [42]\n",
+ " \n",
+ " dates, times, animals, counts = filter_animals('Elk', sample_dates, sample_times, sample_animals, sample_counts)\n",
" \n",
- " assert fdate == ['2011-04-23', '2011-04-23']\n",
- " assert ftime == ['14:12', '10:24']\n",
- " assert fanimal == ['Elk', 'Elk']\n",
- " assert fcount == [25, 26]"
+ " assert dates == sample_dates\n",
+ " assert times == sample_times\n",
+ " assert animals == sample_animals\n",
+ " assert counts == sample_counts"
],
"language": "python",
"metadata": {},
"outputs": [],
- "prompt_number": 37
+ "prompt_number": 54
+ },
+ {
+ "cell_type": "code",
+ "collapsed": false,
+ "input": [
+ "def test_filter_returns_empty_lists_if_animal_not_in_list():\n",
+ " sample_dates = ['2011-04-03', '2011-04-04', '2011-04-04']\n",
+ " sample_times = ['14:12', '18:32', '00:27']\n",
+ " sample_animals = ['Moose', 'Wolverine']\n",
+ " sample_counts = [18, 6]\n",
+ " \n",
+ " dates, times, animals, counts = filter_animals('Elk', sample_dates, sample_times, sample_animals, sample_counts)\n",
+ " \n",
+ " assert dates == []\n",
+ " assert times == []\n",
+ " assert animals == []\n",
+ " assert counts == []"
+ ],
+ "language": "python",
+ "metadata": {},
+ "outputs": [],
+ "prompt_number": 57
},
{
"cell_type": "code",
"outputs": [
{
"html": [
- "<div id=\"ipython_nose_d965cb31197d482394af98b11319a703\"></div>"
+ "<div id=\"ipython_nose_421c36436bd1424eaeea6cc04f73853f\"></div>"
+ ],
+ "output_type": "display_data"
+ },
+ {
+ "javascript": [
+ "document.ipython_nose_421c36436bd1424eaeea6cc04f73853f = $(\"#ipython_nose_421c36436bd1424eaeea6cc04f73853f\");"
+ ],
+ "output_type": "display_data"
+ },
+ {
+ "javascript": [
+ "document.ipython_nose_421c36436bd1424eaeea6cc04f73853f.append($(\"<span>.</span>\"));"
+ ],
+ "output_type": "display_data"
+ },
+ {
+ "javascript": [
+ "document.ipython_nose_421c36436bd1424eaeea6cc04f73853f.append($(\"<span>.</span>\"));"
],
"output_type": "display_data"
},
{
"javascript": [
- "document.ipython_nose_d965cb31197d482394af98b11319a703 = $(\"#ipython_nose_d965cb31197d482394af98b11319a703\");"
+ "document.ipython_nose_421c36436bd1424eaeea6cc04f73853f.append($(\"<span>.</span>\"));"
],
"output_type": "display_data"
},
{
"javascript": [
- "document.ipython_nose_d965cb31197d482394af98b11319a703.append($(\"<span>.</span>\"));"
+ "document.ipython_nose_421c36436bd1424eaeea6cc04f73853f.append($(\"<span>.</span>\"));"
],
"output_type": "display_data"
},
{
"javascript": [
- "document.ipython_nose_d965cb31197d482394af98b11319a703.append($(\"<span>.</span>\"));"
+ "document.ipython_nose_421c36436bd1424eaeea6cc04f73853f.append($(\"<span>.</span>\"));"
],
"output_type": "display_data"
},
{
"javascript": [
- "document.ipython_nose_d965cb31197d482394af98b11319a703.append($(\"<span>.</span>\"));"
+ "document.ipython_nose_421c36436bd1424eaeea6cc04f73853f.append($(\"<span>.</span>\"));"
],
"output_type": "display_data"
},
{
"javascript": [
- "document.ipython_nose_d965cb31197d482394af98b11319a703.append($(\"<span>.</span>\"));"
+ "document.ipython_nose_421c36436bd1424eaeea6cc04f73853f.append($(\"<span>.</span>\"));"
],
"output_type": "display_data"
},
{
"javascript": [
- "document.ipython_nose_d965cb31197d482394af98b11319a703.append($(\"<span>.</span>\"));"
+ "document.ipython_nose_421c36436bd1424eaeea6cc04f73853f.append($(\"<span>.</span>\"));"
],
"output_type": "display_data"
},
{
"javascript": [
- "document.ipython_nose_d965cb31197d482394af98b11319a703.append($(\"<span>.</span>\"));"
+ "document.ipython_nose_421c36436bd1424eaeea6cc04f73853f.append($(\"<span>.</span>\"));"
],
"output_type": "display_data"
},
{
"javascript": [
- "delete document.ipython_nose_d965cb31197d482394af98b11319a703;"
+ "document.ipython_nose_421c36436bd1424eaeea6cc04f73853f.append($(\"<span>.</span>\"));"
+ ],
+ "output_type": "display_data"
+ },
+ {
+ "javascript": [
+ "delete document.ipython_nose_421c36436bd1424eaeea6cc04f73853f;"
],
"output_type": "display_data"
},
" <div class=\"nosebar pass rightmost\" style=\"width: 100%\">\n",
" \n",
" </div>\n",
- " 6/6 tests passed\n",
+ " 10/10 tests passed\n",
" </div>\n",
" "
],
"output_type": "pyout",
- "prompt_number": 38,
+ "prompt_number": 58,
"text": [
- "6/6 tests passed\n"
+ "10/10 tests passed\n"
]
}
],
- "prompt_number": 38
+ "prompt_number": 58
},
{
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "d, t, a, c = read_file('animals.txt')\n",
- "filter_animals('Grizzly', d, t, a, c)"
- ],
- "language": "python",
+ "cell_type": "markdown",
"metadata": {},
- "outputs": [
- {
- "output_type": "pyout",
- "prompt_number": 40,
- "text": [
- "(['2011-04-22'], ['21:06'], ['Grizzly'], [36])"
- ]
- }
- ],
- "prompt_number": 40
+ "source": [
+ "What other test cases did you define?"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "***\n",
+ "**Aside: Test refactoring**\n",
+ "\n",
+ "You can see that there is already some reptition just among two test cases. Tests can be refactored to extract common code into helper functions just like production code can. A number of test frameworks exist to aid you with developing clear, succinct test harnesses. Python includes one called `unittest`.\n",
+ "***"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Mean animals\n",
+ "\n",
+ "All that's left is to tie it all together. Fortunately, because we have focused on building small, cohesive, well-factored blocks of code up to this point, writing the final `mean_sightings` function should be straightforward."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Exercise: Write the `mean_sightings` function and its tests\n",
+ "\n",
+ "This function should:\n",
+ "\n",
+ "* Accept the name of the file from which we are to read animal data\n",
+ "* Accept the name of the animal we are interested in catching in the filter\n",
+ "* Return the mean number of animals seen per sighting\n",
+ "* Be tested!"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Results\n",
+ "\n",
+ "When you are done, your code should look something like this."
+ ]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
- "def mean_animals(filename, species):\n",
- " d, t, a, c = read_file(filename)\n",
- " d, t, a, c = filter_animals(species, d, t, a, c)\n",
- " return calc_mean(c)"
+ "def mean_sightings(filename, species):\n",
+ " dates, times, animals, counts = read_sightings_from_file(filename)\n",
+ " dates, times, animals, counts = filter_animals(species, dates, times, animals, counts)\n",
+ " return mean(counts)"
],
"language": "python",
"metadata": {},
"outputs": [],
- "prompt_number": 41
+ "prompt_number": 72
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "And your tests:"
+ ]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
- "def test_mean_animals1():\n",
- " m = mean_animals('animals.txt', 'Elk')\n",
+ "def test_mean_elk_count_in_animals_txt_is_25_5():\n",
+ " m = mean_sightings('animals.txt', 'Elk')\n",
" assert m == 25.5\n",
"\n",
- "def test_mean_animals2():\n",
- " m = mean_animals('animals.txt', 'Grizzly')\n",
+ "def test_mean_grizzly_count_in_animals_txt_is_36():\n",
+ " m = mean_sightings('animals.txt', 'Grizzly')\n",
" assert m == 36"
],
"language": "python",
"metadata": {},
"outputs": [],
- "prompt_number": 42
+ "prompt_number": 75
},
{
"cell_type": "code",
"outputs": [
{
"html": [
- "<div id=\"ipython_nose_237eee0b04e94196a101b786319e18c1\"></div>"
+ "<div id=\"ipython_nose_5c9bfbdef5e84275adfd02c8a2b010f0\"></div>"
+ ],
+ "output_type": "display_data"
+ },
+ {
+ "javascript": [
+ "document.ipython_nose_5c9bfbdef5e84275adfd02c8a2b010f0 = $(\"#ipython_nose_5c9bfbdef5e84275adfd02c8a2b010f0\");"
+ ],
+ "output_type": "display_data"
+ },
+ {
+ "javascript": [
+ "document.ipython_nose_5c9bfbdef5e84275adfd02c8a2b010f0.append($(\"<span>.</span>\"));"
+ ],
+ "output_type": "display_data"
+ },
+ {
+ "javascript": [
+ "document.ipython_nose_5c9bfbdef5e84275adfd02c8a2b010f0.append($(\"<span>.</span>\"));"
+ ],
+ "output_type": "display_data"
+ },
+ {
+ "javascript": [
+ "document.ipython_nose_5c9bfbdef5e84275adfd02c8a2b010f0.append($(\"<span>.</span>\"));"
+ ],
+ "output_type": "display_data"
+ },
+ {
+ "javascript": [
+ "document.ipython_nose_5c9bfbdef5e84275adfd02c8a2b010f0.append($(\"<span>.</span>\"));"
],
"output_type": "display_data"
},
{
"javascript": [
- "document.ipython_nose_237eee0b04e94196a101b786319e18c1 = $(\"#ipython_nose_237eee0b04e94196a101b786319e18c1\");"
+ "document.ipython_nose_5c9bfbdef5e84275adfd02c8a2b010f0.append($(\"<span>.</span>\"));"
],
"output_type": "display_data"
},
{
"javascript": [
- "document.ipython_nose_237eee0b04e94196a101b786319e18c1.append($(\"<span>.</span>\"));"
+ "document.ipython_nose_5c9bfbdef5e84275adfd02c8a2b010f0.append($(\"<span>.</span>\"));"
],
"output_type": "display_data"
},
{
"javascript": [
- "document.ipython_nose_237eee0b04e94196a101b786319e18c1.append($(\"<span>.</span>\"));"
+ "document.ipython_nose_5c9bfbdef5e84275adfd02c8a2b010f0.append($(\"<span>.</span>\"));"
],
"output_type": "display_data"
},
{
"javascript": [
- "document.ipython_nose_237eee0b04e94196a101b786319e18c1.append($(\"<span>.</span>\"));"
+ "document.ipython_nose_5c9bfbdef5e84275adfd02c8a2b010f0.append($(\"<span>.</span>\"));"
],
"output_type": "display_data"
},
{
"javascript": [
- "document.ipython_nose_237eee0b04e94196a101b786319e18c1.append($(\"<span>.</span>\"));"
+ "document.ipython_nose_5c9bfbdef5e84275adfd02c8a2b010f0.append($(\"<span>.</span>\"));"
],
"output_type": "display_data"
},
{
"javascript": [
- "document.ipython_nose_237eee0b04e94196a101b786319e18c1.append($(\"<span>.</span>\"));"
+ "document.ipython_nose_5c9bfbdef5e84275adfd02c8a2b010f0.append($(\"<span>.</span>\"));"
],
"output_type": "display_data"
},
{
"javascript": [
- "document.ipython_nose_237eee0b04e94196a101b786319e18c1.append($(\"<span>.</span>\"));"
+ "document.ipython_nose_5c9bfbdef5e84275adfd02c8a2b010f0.append($(\"<span>.</span>\"));"
],
"output_type": "display_data"
},
{
"javascript": [
- "document.ipython_nose_237eee0b04e94196a101b786319e18c1.append($(\"<span>.</span>\"));"
+ "document.ipython_nose_5c9bfbdef5e84275adfd02c8a2b010f0.append($(\"<span>.</span>\"));"
],
"output_type": "display_data"
},
{
"javascript": [
- "document.ipython_nose_237eee0b04e94196a101b786319e18c1.append($(\"<span>.</span>\"));"
+ "document.ipython_nose_5c9bfbdef5e84275adfd02c8a2b010f0.append($(\"<span>.</span>\"));"
],
"output_type": "display_data"
},
{
"javascript": [
- "delete document.ipython_nose_237eee0b04e94196a101b786319e18c1;"
+ "document.ipython_nose_5c9bfbdef5e84275adfd02c8a2b010f0.append($(\"<span>.</span>\"));"
+ ],
+ "output_type": "display_data"
+ },
+ {
+ "javascript": [
+ "delete document.ipython_nose_5c9bfbdef5e84275adfd02c8a2b010f0;"
],
"output_type": "display_data"
},
" <div class=\"nosebar pass rightmost\" style=\"width: 100%\">\n",
" \n",
" </div>\n",
- " 8/8 tests passed\n",
+ " 14/14 tests passed\n",
" </div>\n",
" "
],
"output_type": "pyout",
- "prompt_number": 43,
+ "prompt_number": 76,
"text": [
- "8/8 tests passed\n"
+ "14/14 tests passed\n"
]
}
],
- "prompt_number": 43
+ "prompt_number": 76
},
{
- "cell_type": "code",
- "collapsed": false,
- "input": [],
- "language": "python",
+ "cell_type": "markdown",
"metadata": {},
- "outputs": []
+ "source": [
+ "You can have high confidence in the reliability of this function, because it is *composed* of calls to verified functions."
+ ]
}
],
"metadata": {}