Exercises in Software carpentry

Before you start, copy the contents of the subfolder carpentry_exercises into your exercise repository.

Exercise 1 – Writing a test suite [basic]

Goals: Write a test suite using the unittest module.

Write a test file, test_center.py, that tests the function center from the module string (http://docs.python.org/library/string.html#string.center). At each step, run the tests and make sure they pass.

In the file, write three test cases:

a) The first test case checks the functionality of the function, leaving the argument fillchar set to its default value. Control that the function works as advertised for

  1. odd and even widths
  2. a width smaller than the length of the string
  3. an empty input string
  4. a string containing spaces to either extremity Test that the length of the returned string is correct and that it looks like you expect it to. Hint: when the number of spaces to be added is odd, there are two possible ways to center a string. The docstring does not specify which one is correct, so you should test that the returned string is one or the other.

b) The second test case checks the functionality of string.center, with fillchar set to specific values. Test using a letter, a numerical value, and the default value.

c) Finally, test that string.center raises a TypeError when fillchar is set to an empty string, and to a string longer than one character.

Exercise 2 – Testing with numpy and numerical fuzzing [basic]

Goals: Use the numpy.testing utility functions and numerical fuzzing techniques to test numerical code.

Write a new test suite, test_multinomial.py, to test the function numpy.random.multinomial (http://tinyurl.com/448f5dz).

a) Read the documentation and play with the function using ipython until you are sure you understand how it works (always leave the size argument to its default value).

b) Write a first test case, testing the function in deterministic cases:

  1. when one of the entries has probability 1.0 and the others 0.0, the returned samples must consist only of the entry with probability mass
  2. when one of the entries has probability 0.0, it must not appear in the returned samples

c) Write a numerical fuzzing test case that verifies that, with a large number of samples, the sampling frequency of each entry is close to its probability.

Exercise 3 – Deceivingly simple function [intermediate]

Goals: General practice of debugging and unit testing using agile development techniques.

Enter the directory deceivingly_simple. The file maxima.py contains a function, find_maxima, that finds local maxima in a list and returns their indices. Please read the last sentence again: it returns the indices, not the values. ;)

a) Using ipython, test the function with these input arguments and others of your own invention until you are satisfied that it does the right thing for typical cases (remember that the function returns the indices of the maxima):

x = [0, 1, 2, 1, 2, 1, 0]
x = [-i**2 for i in range(-3, 4)]
x = [numpy.sin(2*alpha) for alpha in numpy.linspace(0.0, 5.0, 100)]

b) Now try with the following inputs:

 x = [4, 2, 1, 3, 1, 2]
 x = [4, 2, 1, 3, 1, 5]
 x = [4, 2, 1, 3, 1]

For each bug you find, solve it using the agile programming strategy:

i. Isolate the bug using a debugger

ii. Write a new test case that reproduces the bug. Try to make the test case as simple as possible; here, this means using the simplest input data that still triggers the bug

iii. Correct the code

iv. Makesurethatallthetestspass

c) You may think that the code is now clean and robust... Look at the output of the function for the input list

x = [1, 2, 2, 1]

Does the output correspond to your intuition? Think about a reasonable default behavior in this situation, and meditate on how such a simple function can hide so many complications

d) (optional) Implement the “reasonable behavior” you conceived in c), adding a new test. Make sure that your function handles these inputs correctly (include them in the tests):

x = [1, 2, 2, 3, 1]
x = [1, 3, 2, 2, 1]
x = [3, 2, 2, 3]

e) (optional) Run a coverage analysis on the tests; there should be at least one statement that is not covered. Write a test that covers it and debug the code.