Doctest

Last updated

doctest is a module included in the Python programming language's standard library that allows the easy generation of tests based on output from the standard Python interpreter shell, cut and pasted into docstrings.

Contents

Implementation specifics

Doctest makes innovative [1] use of the following Python capabilities: [2]

When using the Python shell, the primary prompt: >>> , is followed by new commands. The secondary prompt: ... , is used when continuing commands on multiple lines; and the result of executing the command is expected on following lines. A blank line, or another line starting with the primary prompt is seen as the end of the output from the command.

The doctest module looks for such sequences of prompts in a docstring, re-executes the extracted command and checks the output against the output of the command given in the docstrings test example.

The default action when running doctests is for no output to be shown when tests pass. This can be modified by options to the doctest runner. In addition, doctest has been integrated with the Python unit test module allowing doctests to be run as standard unittest testcases. Unittest testcase runners allow more options when running tests such as the reporting of test statistics such as tests passed, and failed.

Literate programming and doctests

Although doctest does not allow a Python program to be embedded in narrative text, it does allow for verifiable examples to be embedded in docstrings, where the docstrings can contain other text. Docstrings can in turn be extracted from program files to generate documentation in other formats such as HTML or PDF. A program file can be made to contain the documentation, tests, as well as the code and the tests easily verified against the code. This allows code, tests, and documentation to evolve together.

Documenting libraries by example

Doctests are well suited to provide an introduction to a library by demonstrating how the API is used.

On the basis of the output of Python's interactive interpreter, text can be mixed with tests that exercise the library, showing expected results.

Examples

Example one shows how narrative text can be interspersed with testable examples in a docstring. In the second example, more features of doctest are shown, together with their explanation. Example three is set up to run all doctests in a file when the file is run, but when imported as a module, the tests will not be run.

Example 1: A doctest embedded in the docstring of a function

deflist_to_0_index(lst):"""A solution to the problem given in:    https://rgrig.blogspot.com/2005/11/writing-readable-code.html    'Given a list, lst, say for each element the 0-index where it appears for    the first time. So the list x = [0, 1, 4, 2, 4, 1, 0, 2] is    transformed into y = [0, 1, 2, 3, 2, 1, 0, 3]. Notice that for all    i we have x[y[i]] = x[i]. Use any programming language and any data    representation you want.'    >>> x = [0, 1, 4, 2, 4, 1, 0, 2]    >>> list_to_0_index(x)    [0, 1, 2, 3, 2, 1, 0, 3]    >>>    """return[lst.index(i)foriinlst]

Example 2: doctests embedded in a README.txt file

======================Demonstration doctests======================This is just an example of what a README text looks like that can be used withthe doctest.DocFileSuite() function from Python's doctest module.Normally, the README file would explain the API of the module, like this:>>> a=1>>> b=2>>> a+b3Notice, that we just demonstrated how to add two numbers in Python, and what the result will look like.A special option allows you to be somewhat fuzzy about your examples:>>> o=object()>>> o# doctest: +ELLIPSIS<object object at 0x...>Exceptions can be tested very nicely too:>>> xTraceback (most recent call last):...NameError: name 'x' is not defined

Example 3: unique_words.py

This example also simulates input to the function from a file by using the Python StringIO module

defunique_words(page):"""Return set of the unique words in list of lines of text.    Example:    >>> from StringIO import StringIO    >>> fileText = '''the cat sat on the mat    ... the mat was ondur the cat    ... one fish two fish red fish    ... blue fish    ... This fish has a yellow car    ... This fish has a yellow star'''    >>> file = StringIO(fileText)    >>> page = file.readlines()    >>> words = unique_words(page)    >>> print sorted(list(words))    ["This", "a", "blue", "car", "cat", "fish", "has", "mat",     "on", "ondur", "one", "red", "sat", "star", "the", "two",     "was", "yellow"]    >>>    """returnset(wordforlineinpageforwordinline.split())def_test():importdoctestdoctest.testmod()if__name__=="__main__":_test()

Doctest and documentation generators

Both the EpyText format of Epydoc and Docutils' reStructuredText format support the markup of doctest sections within docstrings.

Implementation in other programming languages

In C++, the doctest framework is the closest possible implementation of the concept - tests can be written directly in the production code with minimal overhead and the option to strip them from the binary. [3]

The ExUnit.DocTest Elixir library implements functionality similar to Doctest. [4]

An implementation of Doctest for Haskell. [5]

Writing documentation tests in Elm. [6]

Writing documentation tests in Rust. [7]

Writing documentation tests in Elixir. [8]

byexample [9] supports writing doctests for several popular programming languages (e.g. Python, Ruby, Shell, JavaScript, C/C++, Java, Go, Rust) inside Markdown, reStructuredText and other text documents.

Related Research Articles

<span class="mw-page-title-main">Macro (computer science)</span> Rule for substituting a set input with a set output

In computer programming, a macro is a rule or pattern that specifies how a certain input should be mapped to a replacement output. Applying a macro to an input is known as macro expansion. The input and output may be a sequence of lexical tokens or characters, or a syntax tree. Character macros are supported in software applications to make it easy to invoke common command sequences. Token and tree macros are supported in some programming languages to enable code reuse or to extend the language, sometimes for domain-specific languages.

In computing, serialization is the process of translating a data structure or object state into a format that can be stored or transmitted and reconstructed later. When the resulting series of bits is reread according to the serialization format, it can be used to create a semantically identical clone of the original object. For many complex objects, such as those that make extensive use of references, this process is not straightforward. Serialization of objects does not include any of their associated methods with which they were previously linked.

In computer science, control flow is the order in which individual statements, instructions or function calls of an imperative program are executed or evaluated. The emphasis on explicit control flow distinguishes an imperative programming language from a declarative programming language.

In some programming languages, eval, short for the English evaluate, is a function which evaluates a string as though it were an expression in the language, and returns a result; in others, it executes multiple lines of code as though they had been included instead of the line including the eval. The input to eval is not necessarily a string; it may be structured representation of code, such as an abstract syntax tree, or of special type such as code. The analog for a statement is exec, which executes a string as if it were a statement; in some languages, such as Python, both are present, while in other languages only one of either eval or exec is.

In computing, gettext is an internationalization and localization system commonly used for writing multilingual programs on Unix-like computer operating systems. One of the main benefits of gettext is that it separates programming from translating. The most commonly used implementation of gettext is GNU gettext, released by the GNU Project in 1995. The runtime library is libintl. gettext provides an option to use different strings for any number of plural forms of nouns, but this feature has no support for grammatical gender. The main filename extensions used by this system are .POT, .PO and .MO.

Plain Old Documentation (pod) is a lightweight markup language used to document the Perl programming language as well as Perl modules and programs.

Embedded Ruby is a templating system that embeds Ruby into a text document. It is often used to embed Ruby code in an HTML document, similar to ASP and JSP, and PHP and other server-side scripting languages. The templating system of eRuby combines Ruby code and plain text to provide flow control and variable substitution, thus making the combined code easier to maintain.

<span class="mw-page-title-main">Jinja (template engine)</span> Template engine for the Python programming language associated with the Flask framework

Jinja is a web template engine for the Python programming language. It was created by Armin Ronacher and is licensed under a BSD License. Jinja is similar to the Django template engine but provides Python-like expressions while ensuring that the templates are evaluated in a sandbox. It is a text-based template language and thus can be used to generate any markup as well as source code.

In programming, a docstring is a string literal specified in source code that is used, like a comment, to document a specific segment of code. Unlike conventional source code comments, or even specifically formatted comments like docblocks, docstrings are not stripped from the source tree when it is parsed and are retained throughout the runtime of the program. This allows the programmer to inspect these comments at run time, for instance as an interactive help system, or as metadata.

<span class="mw-page-title-main">Python syntax and semantics</span> Set of rules defining correctly structured programs

The syntax of the Python programming language is the set of rules that defines how a Python program will be written and interpreted. The Python language has many similarities to Perl, C, and Java. However, there are some definite differences between the languages. It supports multiple programming paradigms, including structured, object-oriented programming, and functional programming, and boasts a dynamic type system and automatic memory management.

Haxe is a high-level cross-platform programming language and compiler that can produce applications and source code for many different computing platforms from one code-base. It is free and open-source software, released under an MIT License. The compiler, written in OCaml, is released under the GNU General Public License (GPL) version 2.

This comparison of programming languages compares the features of language syntax (format) for over 50 computer programming languages.

<span class="mw-page-title-main">Comment (computer programming)</span> Explanatory note in the source code of a computer program

In computer programming, a comment is a programmer-readable explanation or annotation in the source code of a computer program. They are added with the purpose of making the source code easier for humans to understand, and are generally ignored by compilers and interpreters. The syntax of comments in various programming languages varies considerably.

Protocol Buffers (Protobuf) is a free and open-source cross-platform data format used to serialize structured data. It is useful in developing programs that communicate with each other over a network or for storing data. The method involves an interface description language that describes the structure of some data and a program that generates source code from that description for generating or parsing a stream of bytes that represents the structured data.

The Wing Python IDE is a family of integrated development environments (IDEs) from Wingware created specifically for the Python programming language with support for editing, testing, debugging, inspecting/browsing, and error-checking Python code.

Different command-line argument parsing methods are used by different programming languages to parse command-line arguments.

<span class="mw-page-title-main">Spyder (software)</span> IDE for scientific programming in Python

Spyder is an open-source cross-platform integrated development environment (IDE) for scientific programming in the Python language. Spyder integrates with a number of prominent packages in the scientific Python stack, including NumPy, SciPy, Matplotlib, pandas, IPython, SymPy and Cython, as well as other open-source software. It is released under the MIT license.

Elixir is a functional, concurrent, high-level general-purpose programming language that runs on the BEAM virtual machine, which is also used to implement the Erlang programming language. Elixir builds on top of Erlang and shares the same abstractions for building distributed, fault-tolerant applications. Elixir also provides tooling and an extensible design. The latter is supported by compile-time metaprogramming with macros and polymorphism via protocols.

<span class="mw-page-title-main">Cuneiform (programming language)</span> Open-source workflow language

Cuneiform is an open-source workflow language for large-scale scientific data analysis. It is a statically typed functional programming language promoting parallel computing. It features a versatile foreign function interface allowing users to integrate software from many external programming languages. At the organizational level Cuneiform provides facilities like conditional branching and general recursion making it Turing-complete. In this, Cuneiform is the attempt to close the gap between scientific workflow systems like Taverna, KNIME, or Galaxy and large-scale data analysis programming models like MapReduce or Pig Latin while offering the generality of a functional programming language.

pytest Software testing framework

Pytest is a Python testing framework that originated from the PyPy project. It can be used to write various types of software tests, including unit tests, integration tests, end-to-end tests, and functional tests. Its features include parametrized testing, fixtures, and assert re-writing.

References