开发者

Using Clojure to unit test Java

开发者 https://www.devze.com 2023-01-26 14:40 出处:网络
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

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]}}
0

精彩评论

暂无评论...
验证码 换一张
取 消