How can you “parameterize” Clojure Contrib's test-is?
-
18-09-2019 - |
Question
Both Junit and TestNG provide mechanisms for iterating over a collection of input parameters and running your tests against them. In Junit this is supported via the Parameterized annotation, while TestNG uses @DataProvider.
How can you write data-driven tests using the test-is library? I tried using for list comprehension to iterate over an input parameter collection, but because deftest is a macro it's expecting is clauses.
Solution
From reading the article on parameterized tests in Junit it seems that once you get past the poiler plate the cool part of parameterization is that it lets you type this:
return Arrays.asList(new Object[][] {
{ 2, true },
{ 6, false },
{ 19, true },
{ 22, false }
and easily define four tests.
in test-is the equivalent (no boiler-plate code required) macro is are
(are [n prime?] (= prime? (is-prime n))
3 true
8 false)
If you want to give your inputs as a map then you could run something like:
(dorun (map #(is (= %2 (is-prime %1))
{ 3 true, 8 false}))
though the are
macro will produce more easily read output.
OTHER TIPS
Not sure I understand the point of parameterized tests, but I would use dynamic binding for this.
user> (def *test-data* [0 1 2 3 4 5])
#'user/*test-data*
user> (deftest foo
(doseq [x *test-data*]
(is (< x 4))))
#'user/foo
user> (run-tests)
Testing user
FAIL in (foo) (NO_SOURCE_FILE:1)
expected: (< x 4)
actual: (not (< 4 4))
FAIL in (foo) (NO_SOURCE_FILE:1)
expected: (< x 4)
actual: (not (< 5 4))
Ran 1 tests containing 6 assertions.
2 failures, 0 errors.
nil
user> (defn run-tests-with-data [data]
(binding [*test-data* data] (run-tests)))
#'user/run-tests-with-data
user> (run-tests-with-data [0 1 2 3])
Testing user
Ran 1 tests containing 4 assertions.
0 failures, 0 errors.
nil
You could rewrite deftest
and run-tests
yourself. It'd be maybe a dozen lines of Clojure to let tests accept parameters in some other way.