In class exercise - HUnit and QuickCheck

In this in class exercise, we will practice our skills using the testing frameworks HUnit and QuickCheck.

Some references you may want to look at

Recall the 4 steps for developing your Unit-tests along with your program.

  1. Write a type for the function. Make its body undefined
  2. Make some examples, and express them as HUnit assertions
  3. Collect all the tests together. By convention we use the name tests to collect all the Unit-tests in one file together.
  4. Then fill in the definition until all tests are passed!

Start by cutting and pasting the program skeleton at the bottom of the page.

For this exercise you will create a Haskell program which defines several functions. Study the problem description below for each function, and then perform the 4 Unit-testing steps to defined your function. Then develop 2 QuickTest properties for each function to stress your definition with random tests.

  1. addOne is a list to list function. Its input is a list of Int, and its output is a list of Int. The output can be obtained from the input by adding 1 to each element. For example: addOne [2,6,7] --> [3,7,8]. Be sure you create enough Unit tests before you start coding.

    What might be a good property to test for this function using quickCheck?

  2. addN is a generalization of addOne. It is a list to list function. Its inputs are and Int and a list of Int, and its output is a list of Int. The output can be obtained from the input by adding the first input to each element of the second input. For example: addN 3 [2,6,7] --> [5,9,10].

    Can you devise a property to test using Quickcheck that uses both addOne and addN?

  3. prefixSums returns a list of numbers.
    1. The number in the first position of the list is the sum of the prefix of the input with length 1.
    2. The number in the second position of the list is the sum of the prefix of the input with length 2.
    3. The number in the third position of the list is the sum of the prefix of the input with length 3, etc.

    This is best illustrated with an example. If the input is [2,6,7,5]

    1. The prefix of the input with length 1 is [2].
    2. The prefix of the input with length 2 is [2,6].
    3. The prefix of the input with length 3 is [2,6,7].
    4. The prefix of the input with length 4 is [2,6,7,5].

    Thus, the result is [2,2+6, 2+6+7, 2+6+7+5] --> [2,8,15,20].

    Hint: the function addN might be useful. Be sure and write this function recursively.

    Can you devise a property to check using Quickcheck that relates the nth and nth+1 elements of the output to to the nth+1 element of the input?

  4. take returns a prefix of a list. The first input is the length of the prefix, and the second input is the list that the prefix is obtained from. Its possible that the list is not long enough to obtain a prefix of the supplied length. In that case return the longest possible prefix. For example:

    1. take 0 [3,4,5] --> []
    2. take 6 [3,4] --> [3,4]
    3. take 3 [2,5,6,7,8] --> [2,5,6]
    4. take 2 [] --> []

    Hint: this function decomposes both its arguments to make recursive calls.


module TestingExerciseSkeleton where

import Test.HUnit  -- (Test(TestCase,TestList),assertEqual,runTestTT)
import Test.QuickCheck


addOne :: [Int] -> [Int]
addOne = undefined

addN:: Int -> [Int] -> [Int]
addN = undefined

prefixSums:: [Int] -> [Int]
prefixSums = undefined

takE:: Int -> [a] -> [a]
takE = undefined

Back to the Daily Record.

Back to the class web-page.