Haskell Project: Unit Testing with Hspec

Up to this point we have written some code, explained type classes, and done a little pattern matching. But we haven't written anything that really *does* anything. Until we have some IO to perform, we will have to find another way to interact with our code. This is a perfect chance to introduce Unit Testing.

If you want to review what we've done so far, here is the previous post [Show, Compare, and Filter][1]. Next post [Intro to Parsers][8].

Broken Code in the repl

Starting where we left off in the previous post. We created a `Date` type that was an instance of type class `Show`.

When we printed the `Date` type in our repl things looked right...as long as we had double digit months and days. We wanted to always get four digit years, two digit months and days.

Our code is broken, and we only detected it by playing around in the repl. Not a good way to do development.

Adding Unit Testing with Hspec

There are tons of Unit Testing suites out there. All with their own reasons as to why they are exactly what you need. I went with [Hspec][2] because I've used Ruby's [RSpec][3] in the past. The Hspec site lists the following features:

- A friendly DSL for defining tests

- Integration with QuickCheck, SmallCheck and HUnit

- Parallel test execution

- Automatic discovery of test files

So it looks like Hspec supports other major unit testing suites which is great in case you need to change for some reason. Friendly DSL and automatic detection are good too.

So lets add Hspec into our Stack build. Editing `todo.cabal`, under the `test-suite` section we need to add a build dependency for `hspec`.

A quick overview of this section. `hs-source-dirs` is the location in the project for tests, and `main-is` defines the main source file that will be executed when running tests. `build-depends` defines all the packages required to build the test binary.

To add in the automatic discovery we need to make a simple modification. Replace `test/Spec.hs` with the following. Yes, the file should contain just this single line.

Now we can just add files to the test directory and they will automatically be included in the test. The naming structure is pretty easy:

Our first test

Now that we have everything configured correctly, and our tests are auto-discovered we can add in our first test: `test/TasksSpec.hs`

The format should be pretty simple to understand and if it doesn't yet, seeing the output might make more sense.

If you'd like to get a full understanding of how this all works check out the [Hspec Documentation][5] over at [Hackage][6]. But the simple way of looking at it you have a description of what you're going go test, and then list what `it` should do.

When we run `stack test` in the command line we will see Stack download, configure and build all the dependencies for Hspec. Once you've done this all new projects will use the local copy so this process will speed up.

Looking at the output we can see the tree of our test spec.

We see that one of our tests passed (double digits) while the other test

failed.

Fix and Retest

From our failure results we can compare our expected to our actual results.

We need to pad single digit numbers with zero. Should be simple by adding in a helper function.

Since we have our tests in place we can just run them again and see if this fixes our issue.

We pass both tests!

Next step is to implement all the tests required for the other type classes we implemented for the other data types. See the [source code][4] for a large example of what that might look like.

Red/Green/Refactor

I thought it might be useful to state that once you have your unit test suite in place, I like to continue development doing a [Test-driven Development][7] technique called "Red/Green/Refactor". Its pretty easy to understand and follow:

- Red: Create a test first before working code. It will fail (with red

colored output)

- Green: Add the required support so test passes (with green colored output)

- Refactor: Code is working and tests pass, refactor while always passing

test

There is nothing saying you have to follow this methodology but I find it to be useful.

Up Next

A diff of all changes in this post are available [here][4].

In the next post we will get a little more complicated and start working with parsers for both text files and user input.

Haskell Project: Show Compare and Filter[1]

Hspec[2]

Rspec [3]

Code [4]

Hspec (Hackage)[5]

Hackage) [6]

TDD [7]

Haskell Project: Intro to Parsers [8]

$ date: 2017-05-10 15:15 $

$ tags: haskell, tutorial, hspec, testing $

-- CC-BY-SA-4.0 jecxjo 2017-05-10

Comments?

back

Proxied content from gemini://gemini.sh0.xyz/log/2017-05-10-haskell-project-unit-testing-with-hspec.gmi

Gemini request details:

Original URL
gemini://gemini.sh0.xyz/log/2017-05-10-haskell-project-unit-testing-with-hspec.gmi
Status code
Success
Meta
text/gemini
Proxied by
kineto

Be advised that no attempt was made to verify the remote SSL certificate.