Using Clojure to unit test Java
One of the ways to get an organization to accept an alternate JVM language is to first use it for unit testing Java code -- "Boss, I am just going to write some unit tests in XXX. It'll never go out into production."
Are there any tutorials for do开发者_JAVA技巧ing this in Clojure?
I have just started using Scala to do this to test a Java REST server. Writing the tests in Scala allows me to embed expected XML output, mock the database calls with literal List
objects, etc., not to mention that traits make it very easy to abstract out common code for the tests.
Basically what you need is clojure.test (or one of the many other clojure test libs) and standard Clojure Java interop.
Example:
(ns example.test-java-util
(:use
[clojure.test])
(:import [java.util HashSet]))
(defn new-empty-set []
(HashSet.))
(deftest test-empty-set
(is (= 0 (.size (new-empty-set))))
(is (= true (.isEmpty (new-empty-set))))
(is (= (new-empty-set) (new-empty-set))))
(deftest test-add-remove
(is (= (new-empty-set)
(doto (new-empty-set)
(.add "xyz")
(.remove "xyz")))))
And you would then run them in a variety of ways. Build tools like Maven using the maven clojure plugin run them automatically as part of "mvn test". In a repl, you can do something like:
example.test-java-util> (run-tests 'example.test-java-util)
Testing example.test-java-util
Ran 1 tests containing 4 assertions.
0 failures, 0 errors.
{:type :summary, :test 1, :pass 4, :fail 0, :error 0}
Here is an example using Leiningen, test.check and assuming a standard Maven layout:
pom.xml
project.clj
src
main
java
quicktest
Discontinuities.java
test
clojure
quicktest
test_discontinuities.clj
The Java function to test:
package quicktest;
public class Discontinuities {
public static double f5(double x) {
return x / (x-5);
}
}
The Clojure test case:
(ns quicktest.test-discontinuities
(:import [quicktest Discontinuities])
(:require [clojure.test :refer :all]
[clojure.test.check :as tc]
[clojure.test.check.generators :as gen]
[clojure.test.check.properties :as prop]
[clojure.test.check.clojure-test :as ct :refer (defspec)]))
(deftest test-single-case
(is (= 2.0 (Discontinuities/f5 10))))
(defspec test-discontinuities 1e4
(prop/for-all [x gen/nat ]
(let [y (Discontinuities/f5 x)]
(is (<= y x)))))
The project:
(defproject quicktest/discontinuities "0.1"
:dependencies [[org.clojure/clojure "1.8.0"]
[org.clojure/test.check "0.9.0"]]
:java-source-paths ["src/main/java"]
:test-paths ["src/test/clojure"])
The pom:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>quicktest</groupId>
<artifactId>discontinuities</artifactId>
<version>0.1</version>
</project>
Run with:
mvn compile
lein deps
lein test
Results
The flaw in the function is quickly found:
FAIL in (test-discontinuities) (test_discontinuities.clj:13)
expected: (<= y x)
actual: (not (<= Infinity 5))
{:test-var "test-discontinuities",
:result false,
:seed 1431128331945,
:failing-size 23,
:num-tests 24,
:fail [5],
:shrunk {:total-nodes-visited 3, :depth 0, :result false, :smallest [5]}}
精彩评论