18

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 doing 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.

1
  • 5
    I think the scala tag is misleading here. Is it really called for? Commented Nov 24, 2010 at 18:10

2 Answers 2

11

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}
Sign up to request clarification or add additional context in comments.

2 Comments

It seems to me that your answer doesn't contain any really usefull information according to question's header. Could you explain what is the best way to insert some clojure tests into standard Java JUnit environment? At the current state we are using TeamCity and the algorithm is the following: all classes annotated with specific annotations are loaded from classpath and trasnfered to JUnit which just invokes all @Test methods. Any help would be appreciated.
Well, if you happen to be using Maven, then I think did provide some useful information on how to write and integrate tests into your environment. I don't know of any way to have tests written in Clojure become part of a TeamCity / JUnit execution. It should be possible to write a test runner that would find and invoke the tests, but that seems like more effort than it's worth.
4

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

3 Comments

I tried following your instructions, devstopfix, and got an exception when running lein test that the .clj file can't be found: Exception in thread "main" java.io.FileNotFoundException: Could not locate quicktest/test_discontinuities__init.class or quicktest/test_discontinuities.clj on classpath: , I wrote up some more complete instructions for reproducing the error. gist.github.com/gregory-nisbet/dc4e67380caad8bf21a3314c84c8d06b
I gave the code above a try and found two issues: 1.- the clojure test should be saved in a file called test_discontinuities.clj (underscore between test and discontinuities), because of a Java specific issue with dashes in class names. 2.- The project.clj file should have "test/clojure" in the :test-paths entry, not just "test". After fixing these 2 things I was able to run the tests with lein test.
@denis-fuenzalida thank you both - I have corrected the typo in the example

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.