Fork me on GitHub

JDoctest
An implementation of Python doctests for Java/Javadoc

C. Scott Ananian


JDoctest is an implementation of Python's doctest for Java, based on the ideas in doctestj and Rhino's doctests.

Unlike doctestj, JDoctest is a javadoc Taglet, rather than a Doclet. It doesn't replace the standard javadoc, it just adds a new @doc.test tag. We also use a multiline format similar to Python's doctest (based on Rhino's implementation) rather than insist on a single evaluated expression, as doctestj does.

Doctest blocks are written in Javascript, using the most recent version of ECMAScript that Rhino supports. Calling from Javascript into Java is straightforward. An example from the top of the net.cscott.jdoctest.JDoctest class:

/**
 * A "@doc.test" tag specifies an interactive javascript
 * session, in an environment where the class' package has been imported.
 * The output of the javascript session should match the output
 * provided.
 *
 * @author C. Scott Ananian
 * @doc.test
 *   This is an example of a test which passes:
 *   js> "a".equals("a")
 *   true
 * @doc.test
 *   This is an example of a test which fails:
 *   js> 1+2
 *   5
 * @doc.test
 *   We can write tests which expect exceptions to be thrown, although
 *   it's a little clunky (implementing doctest.ELLIPSIS or
 *   doctest.IGNORE_EXCEPTION_DETAIL would make this nicer):
 *   js> try {
 *     >   java.lang.String("hi").charAt(3);
 *     > } catch (e) {
 *     >   print(e.javaException.getClass().getName())
 *     > }
 *   java.lang.StringIndexOutOfBoundsException
 * @doc.test
 *   This demonstrates that the current package has been imported:
 *   js> JDoctest
 *   [JavaClass net.cscott.jdoctest.JDoctest]
 *   js> Version.PACKAGE_NAME
 *   jdoctest
 * @doc.test
 *   Note that results referencing object hashes are properly handled in
 *   the output comparison function, even when Rhino gives a different hash
 *   at runtime:
 *   js> o = new java.lang.Object()
 *   java.lang.Object@1d2068d
 *   js> o
 *   java.lang.Object@1d2068d
 *   js> new java.lang.Object()
 *   java.lang.Object@1ac2f9c
 */
public class JDoctest implements Taglet { ... }

View the generated javadoc for this example.

Downloading

JDoctest is currently at version 2.1, which requires JDK 17 or later. You can download the latest version, see recent changes, or browse the source code or API documentation on-line. Version 1.7 is the last release for older JDKs (1.5 through 9). Jdoctest is licensed under the GNU GPL v2 or later.

JDoctest is also on Maven Central, as net.cscott:jdoctest:2.1 (for your tests) and net.cscott:jdoctest-annotations:2.1 (just the @Doctests annotation, for your production code); see the README file for how to use them with Maven or Gradle.

Source code repository

The git repository for jdoctest can be cloned with the following command:

git clone https://github.com/cscott/JDoctest.git

Building from source; installing

To build:

To install:

Invocation

To invoke from the command line:

javadoc -taglet net.cscott.jdoctest.JDoctest \
        -tagletpath lib/jdoctest/jdoctest.jar:lib/jdoctest/rhino-all-1.9.2.jar:bin \
        -J-ea \
        <your other javadoc options go here>

I'm assuming that your source code has been compiled into bin. Note that your compiled class files must be included on the tagletpath so that we can run the doctests. Note that you need to use the -J-ea option if you want assertions to be enabled during the evaluation of the doctests. You can use -J-ea:<your package>... to only enable assertions in your code (not in the entire javadoc tool).

If you are using Apache Ant, the following rule will work:

  <javadoc failonerror="true" ...>
    <taglet name="net.cscott.jdoctest.JDoctest"
            path="lib/jdoctest/jdoctest.jar:lib/jdoctest/rhino-all-1.9.2.jar:bin" />
    <arg value="-J-ea" />
  </javadoc>

As before, replace bin with the appropriate path to your compiled project classes. The -J-ea argument ensures assertions are enabled in your code when doctests are evaluated. If your doctests access private members of your classes, add -J--add-opens=java.base/java.lang=ALL-UNNAMED as well.

You may want to add css rules to make the output prettier. JDoctest has hooks to allow the use of google-code-prettify which will do syntax highlighting on the client side. The build.xml file for JDoctest shows how this is hooked up. The files in src/doc-files should be copied to the top-level source directory of your project. Note that javadoc's directory structure for the generated documentation makes it tedious to link to the top-level doc-files directory from the generated documentation, but we add a <script> tag at the bottom of each javadoc page (using the -bottom option) to make it all work out.

JDoctest can also run your doctests as JUnit tests: annotate a class with @Doctests, and JDoctest's JUnit Platform test engine reports each of its doctests as a separate test. JUnit support was added in JDoctest version 1.5, and moved to JUnit 6 in version 2.0; see the README file included with JDoctest for more details.

Mailing list

Join the JDoctest Announce List on Google Groups to receive mail when new versions of JDoctest are released.

You can also follow the project on github or LiveJournal.

Version Archive

Jdoctest 2.1, released 29-Oct-2026.

Jdoctest 2.0, released 28-Oct-2026.

Jdoctest 1.7, released 28-Oct-2026.

Jdoctest 1.6, released 31-Mar-2014.

Jdoctest 1.5, released 12-Sep-2009.

Jdoctest 1.4, released 09-Mar-2009.

Jdoctest 1.3, released 10-Feb-2009.

Jdoctest 1.2, released 07-Feb-2009.

Jdoctest 1.1, released 05-Feb-2009.

Jdoctest 1.0, released 04-Feb-2009.


C. Scott Ananian
cscott cscott.net