art with code

2009-01-02

Prelude.ml testing

I've been bombing prelude.ml with a barrage of unit tests. Started from the top of the file, moving towards the end. Line 958 of two days ago is now line 1723, which is where I'm currently at. And I've got 1900 lines of code left to test.

At this pace I'll be done after about 2000 extra lines of tests. If I use two days each week and write 400 lines per day, it'll take 2.5 weeks.

I've been finding bugs at a rate of around one per every hundred lines of tests. So there should be 20 bugs lurking in the rest of the codebase. I should keep proper track of that and estimate just how bad code I am writing. And try to learn something about it.

The tests serve three purposes: documenting the code, specifying functionality, and finding bugs. The way I write the tests is by writing special comments, then parsing them into a oUnit test file. So the tests are next to the code they test and take relatively little effort to write. Here's an example:

let showFloat f =
Pcre.replace ~rex:(Pcre.regexp "\\.$") ~templ:".0" (string_of_float f)
(**T
showFloat 1. = "1.0"
showFloat 1.0048 = "1.0048"
showFloat (-0.2) = "-0.2"
showFloat 1e18 = "1e+18"
showFloat 1e-18 = "1e-18"
**)

The (**T ... **) creates an anonymous test that checks that each line in the comment body evaluates to true. The name of an anonymous test consists of the source file name and the line number: if our example was at the top of the file "floats.ml", the test name would be "test_floats_line_3", making it easy to find.

You can also create named tests by adding the test name after the (**T:

(**T showFloat_test
showFloat 1. = "1.0"
**)

And it's also possible to write the oUnit test body explicitly using (***:

(*** showFloat_test
assert_equal (showFloat 1.0) "1.0";
assert_equal (showFloat (-0.2)) "-0.2"
**)

When you want to generate the tests, run tools/make_suite.rb floats.ml > floats_test.ml, preferably in your OMakefile.

No comments:

Blog Archive