Sometimes, the programming lanugage itself can help you with glass box testing. Often, languages provide support to determine if you've excercised every branch. OCaml's support for this comes in a tool called Bisect. Let's do this with our leap_year function from before.
let leap_year y =
y mod 4 = 0
&& (y mod 100 <> 0 || y mod 400 = 0)
val leap_year : int -> bool = <fun>
Now let's write some unit tests. First a helper function:
#require "ounit2"
open OUnit2
let leap_year_test (n, y, b) =
n >:: fun _ -> assert_equal b (leap_year y)
/Users/williambarkoff/.opam/cs3110-2021sp/lib/bytes: added to search path /Users/williambarkoff/.opam/cs3110-2021sp/lib/stdlib-shims: added to search path /Users/williambarkoff/.opam/cs3110-2021sp/lib/stdlib-shims/stdlib_shims.cma: loaded /Users/williambarkoff/.opam/cs3110-2021sp/lib/ocaml/unix.cma: loaded /Users/williambarkoff/.opam/cs3110-2021sp/lib/ounit2/advanced: added to search path /Users/williambarkoff/.opam/cs3110-2021sp/lib/ounit2/advanced/oUnitAdvanced.cma: loaded /Users/williambarkoff/.opam/cs3110-2021sp/lib/ounit2: added to search path /Users/williambarkoff/.opam/cs3110-2021sp/lib/ounit2/oUnit.cma: loaded
val leap_year_test : string * int * bool -> OUnit2.test = <fun>
let tests = List.map leap_year_test [
"non leap year", 2010, false;
(* we'll add some more tests later. *)
]
let suite = "Leap year" >::: tests
val tests : OUnit2.test list =
[OUnitTest.TestLabel ("non leap year",
OUnitTest.TestCase (OUnitTest.Short, <fun>))]
val suite : OUnit2.test =
OUnitTest.TestLabel ("Leap year",
OUnitTest.TestList
[OUnitTest.TestLabel ("non leap year",
OUnitTest.TestCase (OUnitTest.Short, <fun>))])
Now let's run our test suite
(jupyter doesn't like this)
.
Ran: 1 tests in 0.00 seconds.
OK
OK my jupyter notebook doesn't like any of this...
Basically, there's a tool called bisect. It is a coverage tool, tells you which branches you've hit and which you've haven't. Read the textbook chapter 7.4 is the bottom line here.