运行Sage‘s Doctest

对函数进行文档测试可确保该函数按照其文档所声称的那样执行。可以使用一个线程或多个线程执行测试。编译Sage的源代码版本后,可以在整个Sage库、给定目录下的所有模块或仅在指定模块上运行doctest。就本章而言,假设我们已从源代码编译了Sage,并且顶级目录为:

[jdemeyer@localhost sage]$ pwd
/home/jdemeyer/sage

请参阅小节 运行自动文档测试 了解有关赛奇自动化测试流程的信息。文档测试的一般语法如下所示。要对接测试某个版本的Sage库中的模块,请使用以下语法:

/path/to/sage_root/sage -t [--long] /path/to/sage_root/path/to/module.py[x]

哪里 --long 是可选参数(请参见 可选参数 以获得更多选项)。的版本 sage 使用的版本必须与包含我们要停靠测试的模块的Sage版本匹配。Sage模块可以是一个Python脚本(文件扩展名为“.py”),也可以是一个Cython脚本,在这种情况下,它的文件扩展名为“.pyx”。

测试模块

假设我们想运行数独模块中的所有测试 sage/games/sudoku.py 。在终端窗口中,首先我们 cd 添加到本地Sage安装的顶级Sage目录。现在,我们可以开始文档测试,如以下终端会话所示:

[jdemeyer@localhost sage]$ ./sage -t src/sage/games/sudoku.py
Running doctests with ID 2012-07-03-03-36-49-d82849c6.
Doctesting 1 file.
sage -t src/sage/games/sudoku.py
    [103 tests, 3.6 s]
------------------------------------------------------------------------
All tests passed!
------------------------------------------------------------------------
Total time for all tests: 4.8 seconds
    cpu time: 3.6 seconds
    cumulative wall time: 3.6 seconds

测试输出的数字显示,测试数独模块大约需要4秒,而测试所有指定的模块需要相同的时间;所需的总时间包括运行测试的代码的一些启动时间。在本例中,我们只测试了一个模块,因此总测试时间与仅测试一个模块所需的时间大致相同也就不足为奇了。请注意,语法为::

[jdemeyer@localhost sage]$ ./sage -t src/sage/games/sudoku.py
Running doctests with ID 2012-07-03-03-39-02-da6accbb.
Doctesting 1 file.
sage -t src/sage/games/sudoku.py
    [103 tests, 3.6 s]
------------------------------------------------------------------------
All tests passed!
------------------------------------------------------------------------
Total time for all tests: 4.9 seconds
    cpu time: 3.6 seconds
    cumulative wall time: 3.6 seconds

但不是::

[jdemeyer@localhost sage]$ ./sage -t sage/games/sudoku.py
Running doctests with ID 2012-07-03-03-40-53-6cc4f29f.
No files matching sage/games/sudoku.py
No files to doctest

我们也可以先 cd 添加到包含该模块的目录 sudoku.py 并按如下方式对接测试该模块:

[jdemeyer@localhost sage]$ cd src/sage/games/
[jdemeyer@localhost games]$ ls
__init__.py  hexad.py       sudoku.py           sudoku_backtrack.pyx
all.py       quantumino.py  sudoku_backtrack.c
[jdemeyer@localhost games]$ ../../../../sage -t sudoku.py
Running doctests with ID 2012-07-03-03-41-39-95ebd2ff.
Doctesting 1 file.
sage -t sudoku.py
    [103 tests, 3.6 s]
------------------------------------------------------------------------
All tests passed!
------------------------------------------------------------------------
Total time for all tests: 5.2 seconds
    cpu time: 3.6 seconds
    cumulative wall time: 3.6 seconds

在上述所有终端会话中,我们使用本地安装的Sage来测试它自己的模块。即使我们有一个系统范围的Sage安装,使用该版本来对接本地安装的模块也会导致混淆。

您还可以运行Sage doctester,如下所示:

[jdemeyer@localhost sage]$ ./sage -tox -e doctest -- src/sage/games/sudoku.py

看见 开发和测试工具 了解更多关于毒素的信息。

故障排除

要在终端窗口中对接测试Sage安装的模块,我们首先 cd 添加到该Sage安装的顶级目录,也称为 SAGE_ROOT 那个装置的。当我们运行测试时,我们通过语法使用该特定的Sage安装 ./sage ;请注意前面的“点正斜杠” sage 。这是一种预防措施,以防在我们的系统具有多个Sage安装时可能出现的混淆。例如,以下语法是可以接受的,因为我们在当前 SAGE_ROOT **

[jdemeyer@localhost sage]$ ./sage -t src/sage/games/sudoku.py
Running doctests with ID 2012-07-03-03-43-24-a3449f54.
Doctesting 1 file.
sage -t src/sage/games/sudoku.py
    [103 tests, 3.6 s]
------------------------------------------------------------------------
All tests passed!
------------------------------------------------------------------------
Total time for all tests: 4.9 seconds
    cpu time: 3.6 seconds
    cumulative wall time: 3.6 seconds
[jdemeyer@localhost sage]$ ./sage -t "src/sage/games/sudoku.py"
Running doctests with ID 2012-07-03-03-43-54-ac8ca007.
Doctesting 1 file.
sage -t src/sage/games/sudoku.py
    [103 tests, 3.6 s]
------------------------------------------------------------------------
All tests passed!
------------------------------------------------------------------------
Total time for all tests: 4.9 seconds
    cpu time: 3.6 seconds
    cumulative wall time: 3.6 seconds

不推荐使用以下语法,因为我们使用的是系统范围的Sage安装(如果存在):

[jdemeyer@localhost sage]$ sage -t src/sage/games/sudoku.py
sage -t  "src/sage/games/sudoku.py"
**********************************************************************
File "/home/jdemeyer/sage/src/sage/games/sudoku.py", line 515:
    sage: next(h.solve(algorithm='backtrack'))
Exception raised:
    Traceback (most recent call last):
      File "/usr/local/sage/local/bin/ncadoctest.py", line 1231, in run_one_test
        self.run_one_example(test, example, filename, compileflags)
      File "/usr/local/sage/local/bin/sagedoctest.py", line 38, in run_one_example
        OrigDocTestRunner.run_one_example(self, test, example, filename, compileflags)
      File "/usr/local/sage/local/bin/ncadoctest.py", line 1172, in run_one_example
        compileflags, 1) in test.globs
      File "<doctest __main__.example_13[4]>", line 1, in <module>
        next(h.solve(algorithm='backtrack'))###line 515:
    sage: next(h.solve(algorithm='backtrack'))
      File "/home/jdemeyer/.sage/tmp/sudoku.py", line 607, in solve
        for soln in gen:
      File "/home/jdemeyer/.sage/tmp/sudoku.py", line 719, in backtrack
        from sudoku_backtrack import backtrack_all
    ImportError: No module named sudoku_backtrack
**********************************************************************
[...more errors...]
2 items had failures:
   4 of  15 in __main__.example_13
   2 of   8 in __main__.example_14
***Test Failed*** 6 failures.
For whitespace errors, see the file /home/jdemeyer/.sage//tmp/.doctest_sudoku.py
         [21.1 s]

----------------------------------------------------------------------
The following tests failed:


        sage -t  "src/sage/games/sudoku.py"
Total time for all tests: 21.3 seconds

在本例中,我们收到一个错误,因为系统范围的Sage安装与我们用于Sage开发的版本不同(旧)。确保始终使用正确版本的Sage测试文件。

并行测试多个模块

到目前为止,我们已经使用单个线程对Sage库中的模块进行了停靠测试。Sage库中有数百个、甚至数千个模块。用一个线程测试它们都需要几个小时。根据我们的硬件,这可能需要六个小时或更长时间。在多核系统上,并行对接测试可以显著减少测试时间。除非我们还想在并行对接测试时使用我们的计算机,否则我们可以选择将我们系统的所有内核都用于并行测试。

让我们对目录中的所有模块进行doctest,首先使用一个线程,然后使用四个线程。对于本例,假设我们要测试下的所有模块 sage/crypto/ 。我们可以使用类似于上面所示的语法来实现这一点:

[jdemeyer@localhost sage]$ ./sage -t src/sage/crypto
Running doctests with ID 2012-07-03-03-45-40-7f837dcf.
Doctesting 24 files.
sage -t src/sage/crypto/__init__.py
    [0 tests, 0.0 s]
sage -t src/sage/crypto/all.py
    [0 tests, 0.0 s]
sage -t src/sage/crypto/boolean_function.pyx
    [252 tests, 4.4 s]
sage -t src/sage/crypto/cipher.py
    [10 tests, 0.0 s]
sage -t src/sage/crypto/classical.py
    [718 tests, 11.3 s]
sage -t src/sage/crypto/classical_cipher.py
    [130 tests, 0.5 s]
sage -t src/sage/crypto/cryptosystem.py
    [82 tests, 0.1 s]
sage -t src/sage/crypto/lattice.py
    [1 tests, 0.0 s]
sage -t src/sage/crypto/lfsr.py
    [31 tests, 0.1 s]
sage -t src/sage/crypto/stream.py
    [17 tests, 0.1 s]
sage -t src/sage/crypto/stream_cipher.py
    [114 tests, 0.2 s]
sage -t src/sage/crypto/util.py
    [122 tests, 0.2 s]
sage -t src/sage/crypto/block_cipher/__init__.py
    [0 tests, 0.0 s]
sage -t src/sage/crypto/block_cipher/all.py
    [0 tests, 0.0 s]
sage -t src/sage/crypto/block_cipher/miniaes.py
    [430 tests, 1.3 s]
sage -t src/sage/crypto/block_cipher/sdes.py
    [290 tests, 0.9 s]
sage -t src/sage/crypto/mq/__init__.py
    [0 tests, 0.0 s]
sage -t src/sage/crypto/mq/mpolynomialsystem.py
    [320 tests, 9.1 s]
sage -t src/sage/crypto/mq/mpolynomialsystemgenerator.py
    [42 tests, 0.1 s]
sage -t src/sage/crypto/sbox.pyx
    [124 tests, 0.8 s]
sage -t src/sage/crypto/mq/sr.py
    [435 tests, 5.5 s]
sage -t src/sage/crypto/public_key/__init__.py
    [0 tests, 0.0 s]
sage -t src/sage/crypto/public_key/all.py
    [0 tests, 0.0 s]
sage -t src/sage/crypto/public_key/blum_goldwasser.py
    [135 tests, 0.2 s]
------------------------------------------------------------------------
All tests passed!
------------------------------------------------------------------------
Total time for all tests: 38.1 seconds
    cpu time: 29.8 seconds
    cumulative wall time: 35.1 seconds

现在我们做同样的事情,但这一次我们还使用可选参数 --long **

[jdemeyer@localhost sage]$ ./sage -t --long src/sage/crypto/
Running doctests with ID 2012-07-03-03-48-11-c16721e6.
Doctesting 24 files.
sage -t --long src/sage/crypto/__init__.py
    [0 tests, 0.0 s]
sage -t --long src/sage/crypto/all.py
    [0 tests, 0.0 s]
sage -t --long src/sage/crypto/boolean_function.pyx
    [252 tests, 4.2 s]
sage -t --long src/sage/crypto/cipher.py
    [10 tests, 0.0 s]
sage -t --long src/sage/crypto/classical.py
    [718 tests, 10.3 s]
sage -t --long src/sage/crypto/classical_cipher.py
    [130 tests, 0.5 s]
sage -t --long src/sage/crypto/cryptosystem.py
    [82 tests, 0.1 s]
sage -t --long src/sage/crypto/lattice.py
    [1 tests, 0.0 s]
sage -t --long src/sage/crypto/lfsr.py
    [31 tests, 0.1 s]
sage -t --long src/sage/crypto/stream.py
    [17 tests, 0.1 s]
sage -t --long src/sage/crypto/stream_cipher.py
    [114 tests, 0.2 s]
sage -t --long src/sage/crypto/util.py
    [122 tests, 0.2 s]
sage -t --long src/sage/crypto/block_cipher/__init__.py
    [0 tests, 0.0 s]
sage -t --long src/sage/crypto/block_cipher/all.py
    [0 tests, 0.0 s]
sage -t --long src/sage/crypto/block_cipher/miniaes.py
    [430 tests, 1.1 s]
sage -t --long src/sage/crypto/block_cipher/sdes.py
    [290 tests, 0.7 s]
sage -t --long src/sage/crypto/mq/__init__.py
    [0 tests, 0.0 s]
sage -t --long src/sage/crypto/mq/mpolynomialsystem.py
    [320 tests, 7.5 s]
sage -t --long src/sage/crypto/mq/mpolynomialsystemgenerator.py
    [42 tests, 0.1 s]
sage -t --long src/sage/crypto/sbox.pyx
    [124 tests, 0.7 s]
sage -t --long src/sage/crypto/mq/sr.py
    [437 tests, 82.4 s]
sage -t --long src/sage/crypto/public_key/__init__.py
    [0 tests, 0.0 s]
sage -t --long src/sage/crypto/public_key/all.py
    [0 tests, 0.0 s]
sage -t --long src/sage/crypto/public_key/blum_goldwasser.py
    [135 tests, 0.2 s]
------------------------------------------------------------------------
All tests passed!
------------------------------------------------------------------------
Total time for all tests: 111.8 seconds
    cpu time: 106.1 seconds
    cumulative wall time: 108.5 seconds

请注意第一组测试和第二组测试之间的时间差,后者使用可选参数 --long 。Sage库中的许多测试都标有 # long time 因为众所周知,这些都需要很长时间才能读完。而不使用可选的 --long 参数、模块 sage/crypto/mq/sr.py 大概花了五秒钟。使用此可选参数时,运行该模块中的所有测试需要82秒。以下是该模块中的一个函数的片段 sage/crypto/mq/sr.py 一项被标记为耗时很长的文档测试:

def test_consistency(max_n=2, **kwargs):
    r"""
    Test all combinations of ``r``, ``c``, ``e`` and ``n`` in ``(1,
    2)`` for consistency of random encryptions and their polynomial
    systems. `\GF{2}` and `\GF{2^e}` systems are tested. This test takes
    a while.

    INPUT:

    - ``max_n`` -- maximal number of rounds to consider (default: 2)
    - ``kwargs`` -- are passed to the SR constructor

    TESTS:

    The following test called with ``max_n`` = 2 requires a LOT of RAM
    (much more than 2GB).  Since this might cause the doctest to fail
    on machines with "only" 2GB of RAM, we test ``max_n`` = 1, which
    has a more reasonable memory usage. ::

        sage: from sage.crypto.mq.sr import test_consistency
        sage: test_consistency(1)  # long time (80s on sage.math, 2011)
        True
    """

现在,我们使用4个线程并行对接同一目录::

[jdemeyer@localhost sage]$ ./sage -tp 4 src/sage/crypto/
Running doctests with ID 2012-07-07-00-11-55-9b17765e.
Sorting sources by runtime so that slower doctests are run first....
Doctesting 24 files using 4 threads.
sage -t src/sage/crypto/boolean_function.pyx
    [252 tests, 3.8 s]
sage -t src/sage/crypto/block_cipher/miniaes.py
    [429 tests, 1.1 s]
sage -t src/sage/crypto/mq/sr.py
    [432 tests, 5.7 s]
sage -t src/sage/crypto/sbox.pyx
    [123 tests, 0.8 s]
sage -t src/sage/crypto/block_cipher/sdes.py
    [289 tests, 0.6 s]
sage -t src/sage/crypto/classical_cipher.py
    [123 tests, 0.4 s]
sage -t src/sage/crypto/stream_cipher.py
    [113 tests, 0.1 s]
sage -t src/sage/crypto/public_key/blum_goldwasser.py
    [134 tests, 0.1 s]
sage -t src/sage/crypto/lfsr.py
    [30 tests, 0.1 s]
sage -t src/sage/crypto/util.py
    [121 tests, 0.1 s]
sage -t src/sage/crypto/cryptosystem.py
    [79 tests, 0.0 s]
sage -t src/sage/crypto/stream.py
    [12 tests, 0.0 s]
sage -t src/sage/crypto/mq/mpolynomialsystemgenerator.py
    [40 tests, 0.0 s]
sage -t src/sage/crypto/cipher.py
    [3 tests, 0.0 s]
sage -t src/sage/crypto/lattice.py
    [0 tests, 0.0 s]
sage -t src/sage/crypto/block_cipher/__init__.py
    [0 tests, 0.0 s]
sage -t src/sage/crypto/all.py
    [0 tests, 0.0 s]
sage -t src/sage/crypto/public_key/__init__.py
    [0 tests, 0.0 s]
sage -t src/sage/crypto/__init__.py
    [0 tests, 0.0 s]
sage -t src/sage/crypto/public_key/all.py
    [0 tests, 0.0 s]
sage -t src/sage/crypto/mq/__init__.py
    [0 tests, 0.0 s]
sage -t src/sage/crypto/block_cipher/all.py
    [0 tests, 0.0 s]
sage -t src/sage/crypto/mq/mpolynomialsystem.py
    [318 tests, 8.4 s]
sage -t src/sage/crypto/classical.py
    [717 tests, 10.4 s]
------------------------------------------------------------------------
All tests passed!
------------------------------------------------------------------------
Total time for all tests: 12.9 seconds
    cpu time: 30.5 seconds
    cumulative wall time: 31.7 seconds
[jdemeyer@localhost sage]$ ./sage -tp 4 --long src/sage/crypto/
Running doctests with ID 2012-07-07-00-13-04-d71f3cd4.
Sorting sources by runtime so that slower doctests are run first....
Doctesting 24 files using 4 threads.
sage -t --long src/sage/crypto/boolean_function.pyx
    [252 tests, 3.7 s]
sage -t --long src/sage/crypto/block_cipher/miniaes.py
    [429 tests, 1.0 s]
sage -t --long src/sage/crypto/sbox.pyx
    [123 tests, 0.8 s]
sage -t --long src/sage/crypto/block_cipher/sdes.py
    [289 tests, 0.6 s]
sage -t --long src/sage/crypto/classical_cipher.py
    [123 tests, 0.4 s]
sage -t --long src/sage/crypto/util.py
    [121 tests, 0.1 s]
sage -t --long src/sage/crypto/stream_cipher.py
    [113 tests, 0.1 s]
sage -t --long src/sage/crypto/public_key/blum_goldwasser.py
    [134 tests, 0.1 s]
sage -t --long src/sage/crypto/lfsr.py
    [30 tests, 0.0 s]
sage -t --long src/sage/crypto/cryptosystem.py
    [79 tests, 0.0 s]
sage -t --long src/sage/crypto/stream.py
    [12 tests, 0.0 s]
sage -t --long src/sage/crypto/mq/mpolynomialsystemgenerator.py
    [40 tests, 0.0 s]
sage -t --long src/sage/crypto/cipher.py
    [3 tests, 0.0 s]
sage -t --long src/sage/crypto/lattice.py
    [0 tests, 0.0 s]
sage -t --long src/sage/crypto/block_cipher/all.py
    [0 tests, 0.0 s]
sage -t --long src/sage/crypto/public_key/__init__.py
    [0 tests, 0.0 s]
sage -t --long src/sage/crypto/mq/__init__.py
    [0 tests, 0.0 s]
sage -t --long src/sage/crypto/all.py
    [0 tests, 0.0 s]
sage -t --long src/sage/crypto/block_cipher/__init__.py
    [0 tests, 0.0 s]
sage -t --long src/sage/crypto/__init__.py
    [0 tests, 0.0 s]
sage -t --long src/sage/crypto/public_key/all.py
    [0 tests, 0.0 s]
sage -t --long src/sage/crypto/mq/mpolynomialsystem.py
    [318 tests, 9.0 s]
sage -t --long src/sage/crypto/classical.py
    [717 tests, 10.5 s]
sage -t --long src/sage/crypto/mq/sr.py
    [434 tests, 88.0 s]
------------------------------------------------------------------------
All tests passed!
------------------------------------------------------------------------
Total time for all tests: 90.4 seconds
    cpu time: 113.4 seconds
    cumulative wall time: 114.5 seconds

随着线程数量的增加,总测试时间会减少。

对整个SAGE库进行并行测试

主Sage库驻留在目录中 SAGE_ROOT/src/ 。我们可以使用上面描述的语法来使用多个线程对接测试主库。在执行发布管理或修补主Sage库时,发布经理将使用以下命令使用10个线程并行测试库:

[jdemeyer@localhost sage]$ ./sage -tp 10 --long src/

另一种方式是奔跑 make ptestlong ,它构建Sage(如有必要),构建Sage文档(如有必要),然后运行并行文档测试。这将通过读取环境变量来确定线程数 MAKE :如果将其设置为 make -j12 ,然后使用12个线程。如果 MAKE 未设置,则默认情况下使用CPU核心数(由Python函数确定 multiprocessing.cpu_count() ),最小值为2,最大值为8。(当它在 GNU make jobserver ,则Sage将请求最多此数量的作业槽。)

在任何情况下,这都将测试具有多个线程的Sage库:

[jdemeyer@localhost sage]$ make ptestlong

以下任一命令还将对接测试Sage库或其克隆之一:

make test
make check
make testlong
make ptest
make ptestlong

区别在于:

  • make testmake check -这两个命令运行相同的测试集。首先测试Sage标准文档,即驻留在

    • SAGE_ROOT/src/doc/common

    • SAGE_ROOT/src/doc/en

    • SAGE_ROOT/src/doc/fr

    最后,这些命令对接测试Sage库。有关这些命令的更多详细信息,请参阅文件 SAGE_ROOT/Makefile

  • make testlong -此命令文档测试标准文档:

    • SAGE_ROOT/src/doc/common

    • SAGE_ROOT/src/doc/en

    • SAGE_ROOT/src/doc/fr

    然后是Sage类库。Doctest与可选参数一起运行 --long 。请参阅该文件 SAGE_ROOT/Makefile 了解更多细节。

  • make ptest -类似于命令 make testmake check 。但是,doctest是使用如上所述的线程数运行的 make ptestlong

  • make ptestlong -类似于命令 make ptest ,但使用可选参数 --long 进行对接测试。

运行这些测试的底层命令是 sage -t --all 。例如, make ptestlong 执行该命令 sage -t -p --all --long --logfile=logs/ptestlong.log 。因此,如果您想在运行这些测试时添加额外的标志,例如 --verbose ,您可以执行 sage -t -p --all --long --verbose --logfile=path/to/logfile 。这里讨论了一些额外的测试选项;运行 sage -t -h 查看完整的列表。

在Sage类库之外

Doctest还可以很好地处理不在Sage库中的文件。例如,假设我们有一个名为的Python脚本 my_python_script.py **

[mvngu@localhost sage]$ cat my_python_script.py
from sage.all_cmdline import *   # import sage library

def square(n):
    """
    Return the square of n.

    EXAMPLES::

        sage: square(2)
        4
    """
    return n**2

然后我们可以像对接Sage库文件一样对其进行对接测试::

[mvngu@localhost sage]$ ./sage -t my_python_script.py
Running doctests with ID 2012-07-07-00-17-56-d056f7c0.
Doctesting 1 file.
sage -t my_python_script.py
    [1 test, 0.0 s]
------------------------------------------------------------------------
All tests passed!
------------------------------------------------------------------------
Total time for all tests: 2.2 seconds
    cpu time: 0.0 seconds
    cumulative wall time: 0.0 seconds

文档测试也可以在Sage脚本上执行。假设我们有一个名为Sage的脚本 my_sage_script.sage 内容如下:

[mvngu@localhost sage]$ cat my_sage_script.sage
def cube(n):
    r"""
    Return the cube of n.

    EXAMPLES::

        sage: cube(2)
        8
    """
    return n**3

然后,我们可以像对Python文件一样对其进行对接测试::

[mvngu@localhost sage]$ ./sage -t my_sage_script.sage
Running doctests with ID 2012-07-07-00-20-06-82ee728c.
Doctesting 1 file.
sage -t my_sage_script.sage
    [1 test, 0.0 s]
------------------------------------------------------------------------
All tests passed!
------------------------------------------------------------------------
Total time for all tests: 2.5 seconds
    cpu time: 0.0 seconds
    cumulative wall time: 0.0 seconds

或者,我们可以对其进行准备以将其转换为Python脚本,然后对其进行文档测试:

[mvngu@localhost sage]$ ./sage --preparse my_sage_script.sage
[mvngu@localhost sage]$ cat my_sage_script.sage.py
# This file was *autogenerated* from the file my_sage_script.sage.
from sage.all_cmdline import *   # import sage library
_sage_const_3 = Integer(3)
def cube(n):
    r"""
    Return the cube of n.

    EXAMPLES::

        sage: cube(2)
        8
    """
    return n**_sage_const_3
[mvngu@localhost sage]$ ./sage -t my_sage_script.sage.py
Running doctests with ID 2012-07-07-00-26-46-2bb00911.
Doctesting 1 file.
sage -t my_sage_script.sage.py
    [2 tests, 0.0 s]
------------------------------------------------------------------------
All tests passed!
------------------------------------------------------------------------
Total time for all tests: 2.3 seconds
    cpu time: 0.0 seconds
    cumulative wall time: 0.0 seconds

来自Sage内部的文档测试

您可以在Sage中运行doctest,这很有用,因为您不必等待Sage启动。使用 run_doctests 函数,向其传递字符串或模块:

sage: run_doctests(sage.combinat.affine_permutation)
Running doctests with ID 2018-02-07-13-23-13-89fe17b1.
Git branch: develop
Using --optional=sagemath_doc_html,sage
Doctesting 1 file.
sage -t /opt/sage/sage_stable/src/sage/combinat/affine_permutation.py
    [338 tests, 4.32 s]
----------------------------------------------------------------------
All tests passed!
----------------------------------------------------------------------
Total time for all tests: 4.4 seconds
    cpu time: 3.6 seconds
    cumulative wall time: 4.3 seconds

可选参数

运行长时间的文档测试

理想情况下,文档测试不应该花费任何明显的时间。如果您确实需要运行更长时间的文档测试(任何超过一秒的测试),则应将其标记为:

sage: my_long_test()  # long time

即便如此,长时间的博士测试最好能在5秒或更短时间内完成。我们知道您(作者)想要炫耀您的代码的功能,但这里不是这样做的地方。长期运行的测试迟早会损害我们运行测试套件的能力。实际上,文档测试应该在提供代码覆盖率的同时尽可能快。

使用 --long 用于运行已标记有注释的文档测试的标志 # long time 。为了减少运行测试所花费的时间,通常会跳过这些测试:

[roed@localhost sage]$ ./sage -t src/sage/rings/tests.py
Running doctests with ID 2012-06-21-16-00-13-40835825.
Doctesting 1 file.
sage -t tests.py
    [18 tests, 1.1 s]
------------------------------------------------------------------------
All tests passed!
------------------------------------------------------------------------
Total time for all tests: 2.9 seconds
    cpu time: 0.9 seconds
    cumulative wall time: 1.1 seconds

要同时运行长时间测试,请执行以下操作:

[roed@localhost sage]$ ./sage -t --long src/sage/rings/tests.py
Running doctests with ID 2012-06-21-16-02-05-d13a9a24.
Doctesting 1 file.
sage -t tests.py
    [20 tests, 34.7 s]
------------------------------------------------------------------------
All tests passed!
------------------------------------------------------------------------
Total time for all tests: 46.5 seconds
    cpu time: 25.2 seconds
    cumulative wall time: 34.7 seconds

若要查找耗时超过允许时间的测试,请使用 --warn-long 旗帜。在没有任何选项的情况下,如果测试花费的时间超过1.0秒,将导致测试打印警告。请注意,这是警告,而不是错误::

[roed@localhost sage]$ ./sage -t --warn-long src/sage/rings/factorint.pyx
Running doctests with ID 2012-07-14-03-27-03-2c952ac1.
Doctesting 1 file.
sage -t --warn-long src/sage/rings/factorint.pyx
**********************************************************************
File "src/sage/rings/factorint.pyx", line 125, in sage.rings.factorint.base_exponent
Failed example:
    base_exponent(-4)
Test ran for 4.09 s
**********************************************************************
File "src/sage/rings/factorint.pyx", line 153, in sage.rings.factorint.factor_aurifeuillian
Failed example:
    fa(2^6+1)
Test ran for 2.22 s
**********************************************************************
File "src/sage/rings/factorint.pyx", line 155, in sage.rings.factorint.factor_aurifeuillian
Failed example:
    fa(2^58+1)
Test ran for 2.22 s
**********************************************************************
File "src/sage/rings/factorint.pyx", line 163, in sage.rings.factorint.factor_aurifeuillian
Failed example:
    fa(2^4+1)
Test ran for 2.25 s
**********************************************************************
----------------------------------------------------------------------
All tests passed!
----------------------------------------------------------------------
Total time for all tests: 16.1 seconds
    cpu time: 9.7 seconds
    cumulative wall time: 10.9 seconds

您还可以传入一个明确的时间量::

[roed@localhost sage]$ ./sage -t --long --warn-long 2.0 src/sage/rings/tests.py
Running doctests with ID 2012-07-14-03-30-13-c9164c9d.
Doctesting 1 file.
sage -t --long --warn-long 2.0 tests.py
**********************************************************************
File "tests.py", line 240, in sage.rings.tests.test_random_elements
Failed example:
    sage.rings.tests.test_random_elements(trials=1000)  # long time (5 seconds)
Test ran for 13.36 s
**********************************************************************
File "tests.py", line 283, in sage.rings.tests.test_random_arith
Failed example:
    sage.rings.tests.test_random_arith(trials=1000)   # long time (5 seconds?)
Test ran for 12.42 s
**********************************************************************
----------------------------------------------------------------------
All tests passed!
----------------------------------------------------------------------
Total time for all tests: 27.6 seconds
    cpu time: 24.8 seconds
    cumulative wall time: 26.3 seconds

最后,可以使用以下命令禁用有关长时间测试的任何警告 --warn-long 0

Doctest从随机种子开始::

[kliem@localhost sage]$ ./sage -t src/sage/doctest/tests/random_seed.rst
Running doctests with ID 2020-06-23-23-22-59-49f37a55.
...
Doctesting 1 file.
sage -t --warn-long 89.5 --random-seed=112986622569797306072457879734474628454 src/sage/doctest/tests/random_seed.rst
**********************************************************************
File "src/sage/doctest/tests/random_seed.rst", line 3, in sage.doctest.tests.random_seed
Failed example:
    randint(5, 10)
Expected:
    9
Got:
    8
**********************************************************************
1 item had failures:
   1 of   2 in sage.doctest.tests.random_seed
    [1 test, 1 failure, 0.00 s]
----------------------------------------------------------------------
sage -t --warn-long 89.5 --random-seed=112986622569797306072457879734474628454 src/sage/doctest/tests/random_seed.rst  # 1 doctest failed
----------------------------------------------------------------------
Total time for all tests: 0.0 seconds
    cpu time: 0.0 seconds
    cumulative wall time: 0.0 seconds

可以显式设置此种子以重现可能的故障:

[kliem@localhost sage]$ ./sage -t --warn-long 89.5                              \
                          --random-seed=112986622569797306072457879734474628454 \
                          src/sage/doctest/tests/random_seed.rst
Running doctests with ID 2020-06-23-23-24-28-14a52269.
...
Doctesting 1 file.
sage -t --warn-long 89.5 --random-seed=112986622569797306072457879734474628454 src/sage/doctest/tests/random_seed.rst
**********************************************************************
File "src/sage/doctest/tests/random_seed.rst", line 3, in sage.doctest.tests.random_seed
Failed example:
    randint(5, 10)
Expected:
    9
Got:
    8
**********************************************************************
1 item had failures:
   1 of   2 in sage.doctest.tests.random_seed
    [1 test, 1 failure, 0.00 s]
----------------------------------------------------------------------
sage -t --warn-long 89.5 --random-seed=112986622569797306072457879734474628454 src/sage/doctest/tests/random_seed.rst  # 1 doctest failed
----------------------------------------------------------------------
Total time for all tests: 0.0 seconds
    cpu time: 0.0 seconds
    cumulative wall time: 0.0 seconds

也可以使用环境变量显式设置它 SAGE_DOCTEST_RANDOM_SEED

运行可选的文档测试

可以运行需要可选包的测试,方法是使用 --optional 旗帜。显然,您需要安装必要的可选程序包才能使这些测试成功。

默认情况下,Sage仅运行未标记为 optional 标签。这相当于运行::

[roed@localhost sage]$ ./sage -t --optional=sagemath_doc_html,sage \
                              src/sage/rings/real_mpfr.pyx
Running doctests with ID 2012-06-21-16-18-30-a368a200.
Doctesting 1 file.
sage -t src/sage/rings/real_mpfr.pyx
    [819 tests, 7.0 s]
------------------------------------------------------------------------
All tests passed!
------------------------------------------------------------------------
Total time for all tests: 8.4 seconds
    cpu time: 4.1 seconds
    cumulative wall time: 7.0 seconds

如果您还想运行需要岩浆的测试,可以执行以下操作:

[roed@localhost sage]$ ./sage -t --optional=sagemath_doc_html,sage,magma \
                              src/sage/rings/real_mpfr.pyx
Running doctests with ID 2012-06-21-16-18-30-a00a7319
Doctesting 1 file.
sage -t src/sage/rings/real_mpfr.pyx
    [823 tests, 8.4 s]
------------------------------------------------------------------------
All tests passed!
------------------------------------------------------------------------
Total time for all tests: 9.6 seconds
    cpu time: 4.0 seconds
    cumulative wall time: 8.4 seconds

为了只运行标记为需要岩浆的测试,请省略 sagesagemath_doc_html **

[roed@localhost sage]$ ./sage -t --optional=magma src/sage/rings/real_mpfr.pyx
Running doctests with ID 2012-06-21-16-18-33-a2bc1fdf
Doctesting 1 file.
sage -t src/sage/rings/real_mpfr.pyx
    [4 tests, 2.0 s]
------------------------------------------------------------------------
All tests passed!
------------------------------------------------------------------------
Total time for all tests: 3.2 seconds
    cpu time: 0.1 seconds
    cumulative wall time: 2.0 seconds

如果您希望Sage自动检测外部软件或其他功能(如Magma、LaTeX、Internet)并运行所有相关测试,则添加 external **

[roed@localhost sage]$ ./sage -t --optional=external src/sage/rings/real_mpfr.pyx
Running doctests with ID 2016-03-16-14-10-21-af2ebb67.
Using --optional=external
External software to be detected: cplex,gurobi,internet,latex,macaulay2,magma,maple,mathematica,matlab,octave,scilab
Doctesting 1 file.
sage -t --warn-long 28.0 src/sage/rings/real_mpfr.pyx
    [5 tests, 0.04 s]
----------------------------------------------------------------------
All tests passed!
----------------------------------------------------------------------
Total time for all tests: 0.5 seconds
    cpu time: 0.0 seconds
    cumulative wall time: 0.0 seconds
External software detected for doctesting: magma

若要运行所有测试,无论它们是否标记为可选,请传递 all 作为 optional 标签::

[roed@localhost sage]$ ./sage -t --optional=all src/sage/rings/real_mpfr.pyx
Running doctests with ID 2012-06-21-16-31-18-8c097f55
Doctesting 1 file.
sage -t src/sage/rings/real_mpfr.pyx
    [865 tests, 11.2 s]
------------------------------------------------------------------------
All tests passed!
------------------------------------------------------------------------
Total time for all tests: 12.8 seconds
    cpu time: 4.7 seconds
    cumulative wall time: 11.2 seconds

并行运行文档测试

如果您正在测试多个文件,则可以通过使用多个线程获得较大的加速比。若要并行运行文档测试,请使用 --nthreads 旗子 (-p 是一个缩写版本)。传入您要使用的线程数(默认情况下,Sage仅使用1)::

[roed@localhost sage]$ ./sage -tp 2 src/sage/doctest/
Running doctests with ID 2012-06-22-19-09-25-a3afdb8c.
Sorting sources by runtime so that slower doctests are run first....
Doctesting 8 files using 2 threads.
sage -t src/sage/doctest/control.py
    [114 tests, 4.6 s]
sage -t src/sage/doctest/util.py
    [114 tests, 0.6 s]
sage -t src/sage/doctest/parsing.py
    [187 tests, 0.5 s]
sage -t src/sage/doctest/sources.py
    [128 tests, 0.1 s]
sage -t src/sage/doctest/reporting.py
    [53 tests, 0.1 s]
sage -t src/sage/doctest/all.py
    [0 tests, 0.0 s]
sage -t src/sage/doctest/__init__.py
    [0 tests, 0.0 s]
sage -t src/sage/doctest/forker.py
    [322 tests, 15.5 s]
------------------------------------------------------------------------
All tests passed!
------------------------------------------------------------------------
Total time for all tests: 17.0 seconds
    cpu time: 4.2 seconds
    cumulative wall time: 21.5 seconds

对所有的Sage进行文档测试

要对整个Sage库进行停靠测试,请使用 --all 旗子 (-a (简称)。除了测试Sage的Python和Cython文件中的代码外,此命令还将运行Sage的文档中定义的测试以及测试Sage笔记本:

[roed@localhost sage]$ ./sage -t -a
Running doctests with ID 2012-06-22-19-10-27-e26fce6d.
Doctesting entire Sage library.
Sorting sources by runtime so that slower doctests are run first....
Doctesting 2020 files.
sage -t /Users/roed/sage/src/sage/plot/plot.py
    [304 tests, 69.0 s]
...

调试工具

Sometimes doctests fail (that's why we run them after all). There are various flags to help when something goes wrong. If a doctest produces a Python error, then normally tests continue after reporting that an error occurred. If you use the flag --debug (-d for short) then you will drop into an interactive Python debugger whenever a Python exception occurs. As an example, I modified sage.schemes.elliptic_curves.constructor to produce an error:

[roed@localhost sage]$ ./sage -t --debug \
                             src/sage/schemes/elliptic_curves/constructor.py
Running doctests with ID 2012-06-23-12-09-04-b6352629.
Doctesting 1 file.
**********************************************************************
File "sage.schemes.elliptic_curves.constructor", line 4, in sage.schemes.elliptic_curves.constructor
Failed example:
    EllipticCurve([0,0])
Exception raised:
    Traceback (most recent call last):
      File ".../site-packages/sage/doctest/forker.py", line 573, in _run
        self.execute(example, compiled, test.globs)
      File ".../site-packages/sage/doctest/forker.py", line 835, in execute
        exec compiled in globs
      File "<doctest sage.schemes.elliptic_curves.constructor[0]>", line 1, in <module>
        EllipticCurve([Integer(0),Integer(0)])
      File ".../site-packages/sage/schemes/elliptic_curves/constructor.py", line 346, in EllipticCurve
        return ell_rational_field.EllipticCurve_rational_field(x, y)
      File ".../site-packages/sage/schemes/elliptic_curves/ell_rational_field.py", line 216, in __init__
        EllipticCurve_number_field.__init__(self, Q, ainvs)
      File ".../site-packages/sage/schemes/elliptic_curves/ell_number_field.py", line 159, in __init__
        EllipticCurve_field.__init__(self, [field(x) for x in ainvs])
      File ".../site-packages/sage/schemes/elliptic_curves/ell_generic.py", line 156, in __init__
        "Invariants %s define a singular curve."%ainvs
    ArithmeticError: Invariants [0, 0, 0, 0, 0] define a singular curve.
> .../site-packages/sage/schemes/elliptic_curves/ell_generic.py(156)__init__()
-> "Invariants %s define a singular curve."%ainvs
(Pdb) l
151                 if len(ainvs) == 2:
152                     ainvs = [K(0),K(0),K(0)] + ainvs
153                 self.__ainvs = tuple(ainvs)
154                 if self.discriminant() == 0:
155                     raise ArithmeticError(
156  ->                     "Invariants %s define a singular curve."%ainvs)
157                 PP = projective_space.ProjectiveSpace(2, K, names='xyz');
158                 x, y, z = PP.coordinate_ring().gens()
159                 a1, a2, a3, a4, a6 = ainvs
160                 f = y**2*z + (a1*x + a3*z)*y*z \
161                     - (x**3 + a2*x**2*z + a4*x*z**2 + a6*z**3)
(Pdb) p ainvs
[0, 0, 0, 0, 0]
(Pdb) quit
**********************************************************************
1 items had failures:
   1 of   1 in sage.schemes.elliptic_curves.constructor
***Test Failed*** 1 failures.
sage -t src/sage/schemes/elliptic_curves/constructor.py
    [64 tests, 89.2 s]
------------------------------------------------------------------------
sage -t src/sage/schemes/elliptic_curves/constructor.py # 1 doctest failed
------------------------------------------------------------------------
Total time for all tests: 90.4 seconds
    cpu time: 4.5 seconds
    cumulative wall time: 89.2 seconds

有时,错误可能非常严重,导致Sage分段错误或挂起。在这种情况下,你有很多选择。到目前为止,doctest框架将打印出输出,这样您至少可以知道是什么测试导致了问题(如果您希望此输出实时显示,请使用 --verbose 旗帜)。要使doctest在gdb的控制下运行,请使用 --gdb 旗帜::

[roed@localhost sage]$ ./sage -t --gdb \
                              src/sage/schemes/elliptic_curves/constructor.py
exec gdb --eval-commands="run" --args /home/roed/sage/local/var/lib/sage/venv-python3.9/bin/python3 sage-runtests --serial --timeout=0 --stats-path=/home/roed/.sage/timings2.json --optional=pip,sage,sage_spkg src/sage/schemes/elliptic_curves/constructor.py
GNU gdb 6.8-debian
Copyright (C) 2008 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu"...
[Thread debugging using libthread_db enabled]
[New Thread 0x7f10f85566e0 (LWP 6534)]
Running doctests with ID 2012-07-07-00-43-36-b1b735e7.
Doctesting 1 file.
sage -t src/sage/schemes/elliptic_curves/constructor.py
    [67 tests, 5.8 s]
------------------------------------------------------------------------
All tests passed!
------------------------------------------------------------------------
Total time for all tests: 15.7 seconds
    cpu time: 4.4 seconds
    cumulative wall time: 5.8 seconds

Program exited normally.
(gdb) quit

Sage还包括valgrind,您可以在各种valgrind工具下运行文档测试来跟踪内存问题:相关标志是 --valgrind (或 --memcheck ), --massif--cachegrind--omega 。有关更多详细信息,请参阅http://wiki.sagemath.org/ValgrindingSage。

修复完doctest所揭示的任何问题后,您可以使用 --failed 旗子 (-f 简称)::

[roed@localhost sage]$ ./sage -t -fa
Running doctests with ID 2012-07-07-00-45-35-d8b5a408.
Doctesting entire Sage library.
Only doctesting files that failed last test.
No files to doctest

其他选项

还有各种其他选项可以更改Sage的文档测试代码的行为。

仅显示第一个失败

文件中的第一个失败通常会导致一系列其他错误,因为NameError是由未定义的变量引起的,而测试失败则是因为使用了旧的变量值。若要仅查看每个doctest块中的第一个失败,请使用 --initial 旗子 (-i (简称)。

显示跳过的可选测试

若要在每个文件的末尾打印摘要并跳过可选测试的数量,请使用 --show-skipped 旗帜::

[roed@localhost sage]$ ./sage -t --show-skipped \
                              src/sage/rings/finite_rings/integer_mod.pyx
Running doctests with ID 2013-03-14-15-32-05-8136f5e3.
Doctesting 1 file.
sage -t sage/rings/finite_rings/integer_mod.pyx
    2 axiom tests not run
    1 cunningham test not run
    2 fricas tests not run
    1 long test not run
    3 magma tests not run
    [440 tests, 4.0 s]
----------------------------------------------------------------------
All tests passed!
----------------------------------------------------------------------
Total time for all tests: 4.3 seconds
    cpu time: 2.4 seconds
    cumulative wall time: 4.0 seconds

使用迭代运行测试

有时测试会间歇性地失败。有两个选项允许您重复运行测试以尝试搜索Heisenbugs。旗帜 --global-iterations 获取一个整数,并按顺序多次运行整套测试:

[roed@localhost sage]$ ./sage -t --global-iterations 2 src/sage/sandpiles
Running doctests with ID 2012-07-07-00-59-28-e7048ad9.
Doctesting 3 files (2 global iterations).
sage -t src/sage/sandpiles/__init__.py
    [0 tests, 0.0 s]
sage -t src/sage/sandpiles/all.py
    [0 tests, 0.0 s]
sage -t src/sage/sandpiles/sandpile.py
    [711 tests, 14.7 s]
------------------------------------------------------------------------
All tests passed!
------------------------------------------------------------------------
Total time for all tests: 17.6 seconds
    cpu time: 13.2 seconds
    cumulative wall time: 14.7 seconds
sage -t src/sage/sandpiles/__init__.py
    [0 tests, 0.0 s]
sage -t src/sage/sandpiles/all.py
    [0 tests, 0.0 s]
sage -t src/sage/sandpiles/sandpile.py
    [711 tests, 13.8 s]
------------------------------------------------------------------------
All tests passed!
------------------------------------------------------------------------
Total time for all tests: 14.3 seconds
    cpu time: 26.4 seconds
    cumulative wall time: 28.5 seconds

您还可以按不同的顺序进行迭代: --file-iterations 标志在每个文件中运行测试 N 继续之前的次数::

[roed@localhost sage]$ ./sage -t --file-iterations 2 src/sage/sandpiles
Running doctests with ID 2012-07-07-01-01-43-8f954206.
Doctesting 3 files (2 file iterations).
sage -t src/sage/sandpiles/__init__.py
    [0 tests, 0.0 s]
sage -t src/sage/sandpiles/all.py
    [0 tests, 0.0 s]
sage -t src/sage/sandpiles/sandpile.py
    [1422 tests, 13.3 s]
------------------------------------------------------------------------
All tests passed!
------------------------------------------------------------------------
Total time for all tests: 29.6 seconds
    cpu time: 12.7 seconds
    cumulative wall time: 13.3 seconds

请注意,报告的结果是该文件中所有测试完成的平均时间。如果文件中出现故障,则会报告该故障,并继续测试下一个文件。

使用不同的超时

在速度较慢的计算机上,5分钟的默认超时可能不足以处理最慢的文件。使用 --timeout 旗子 (-T 简写)将其设置为其他内容::

[roed@localhost sage]$ ./sage -tp 2 --all --timeout 1
Running doctests with ID 2012-07-07-01-09-37-deb1ab83.
Doctesting entire Sage library.
Sorting sources by runtime so that slower doctests are run first....
Doctesting 2067 files using 2 threads.
sage -t src/sage/schemes/elliptic_curves/ell_rational_field.py
    Timed out!
...

使用绝对路径

默认情况下,使用相对路径打印文件名。使用绝对路径,而不是在 --abspath 旗帜::

[roed@localhost sage]$ ./sage -t --abspath src/sage/doctest/control.py
Running doctests with ID 2012-07-07-01-13-03-a023e212.
Doctesting 1 file.
sage -t /home/roed/sage/src/sage/doctest/control.py
    [133 tests, 4.7 s]
------------------------------------------------------------------------
All tests passed!
------------------------------------------------------------------------
Total time for all tests: 7.1 seconds
    cpu time: 0.2 seconds
    cumulative wall time: 4.7 seconds

测试已更改的文件

如果您正在处理Sage库中的某些文件,则只测试已更改的文件可能比较方便。为此,请使用 --new 标志,用于测试自上次提交以来修改或添加的文件::

[roed@localhost sage]$ ./sage -t --new
Running doctests with ID 2012-07-07-01-15-52-645620ee.
Doctesting files changed since last git commit.
Doctesting 1 file.
sage -t src/sage/doctest/control.py
    [133 tests, 3.7 s]
------------------------------------------------------------------------
All tests passed!
------------------------------------------------------------------------
Total time for all tests: 3.8 seconds
    cpu time: 0.1 seconds
    cumulative wall time: 3.7 seconds

以随机顺序运行测试

默认情况下,测试按照它们在文件中出现的顺序运行。若要以随机顺序运行测试(这可能会揭示细微的错误),请使用 --randorder 标记并传入随机种子::

[roed@localhost sage]$ ./sage -t --new --randorder 127
Running doctests with ID 2012-07-07-01-19-06-97c8484e.
Doctesting files changed since last git commit.
Doctesting 1 file.
sage -t src/sage/doctest/control.py
    [133 tests, 3.6 s]
------------------------------------------------------------------------
All tests passed!
------------------------------------------------------------------------
Total time for all tests: 3.7 seconds
    cpu time: 0.2 seconds
    cumulative wall time: 3.6 seconds

请注意,即使使用此选项,给定doctest块中的测试仍将按顺序运行。

测试外部文件

测试不属于程序包的文件时(该文件不在包含 __init__.py 文件),则测试代码在运行测试之前将全局变量从该文件加载到命名空间。若要禁用此行为(并要求显式指定导入),请使用 --force-lib 选择。

辅助档案

指定日志文件(而不是使用为其创建的缺省值 sage -t --all ),请使用 --logfile 旗帜::

[roed@localhost sage]$ ./sage -t --logfile test1.log src/sage/doctest/control.py
Running doctests with ID 2012-07-07-01-25-49-e7c0e52d.
Doctesting 1 file.
sage -t src/sage/doctest/control.py
    [133 tests, 4.3 s]
------------------------------------------------------------------------
All tests passed!
------------------------------------------------------------------------
Total time for all tests: 6.7 seconds
    cpu time: 0.1 seconds
    cumulative wall time: 4.3 seconds
[roed@localhost sage]$ cat test1.log
Running doctests with ID 2012-07-07-01-25-49-e7c0e52d.
Doctesting 1 file.
sage -t src/sage/doctest/control.py
    [133 tests, 4.3 s]
------------------------------------------------------------------------
All tests passed!
------------------------------------------------------------------------
Total time for all tests: 6.7 seconds
    cpu time: 0.1 seconds
    cumulative wall time: 4.3 seconds

若要提供存储每个文件的计时和通过/失败状态的json文件,请使用 --stats-path 标志;此文件的默认位置为 ~/.sage/timings2.json 。文档测试员读取它(如果它存在),以便对文件进行分类,以便首先运行较慢的测试(从而最有效地利用多个进程):

[roed@localhost sage]$ ./sage -tp 2 --stats-path ~/.sage/timings2.json --all
Running doctests with ID 2012-07-07-01-28-34-2df4251d.
Doctesting entire Sage library.
Sorting sources by runtime so that slower doctests are run first....
Doctesting 2067 files using 2 threads.
...

在doctest运行结束时,Sage更新json文件(如果它存在)或创建一个新文件。

记录的文件通过/失败状态可用于仅运行未通过其最近一次测试的文件,方法是使用 --failed 旗子 (-f (简称)。

使用选项 --baseline-stats-path known-test-failures.json ,可以区分已知文档测试失败的文件和新失败的文件。档案 known-test-failures.json 应按以下格式准备 timings2.json

在那里标记为失败的源文件将被标记为“ [failed in baseline] “文档测试报告中的故障;如果只有基准故障,没有新故障,则 sage -t 将退出,状态代码为0(成功)。

在虚拟环境中进行测试的选项

模块化Sage库的分发包可以在虚拟环境中进行测试。Sage拥有使用以下工具创建此类虚拟环境的基础架构 tox ,这一点在 测试分发包 。本节中的示例指的是此设置,但它也适用于任何用户创建的虚拟环境。

在以下目录中设置的虚拟环境 pkgs/sagemath-standard/.tox/sagepython-sagewheels-nopypi-norequirements 包含内置(不可编辑)控制盘的安装。

要测试安装在虚拟环境中的所有Sage模块,请使用选项 --installed (而不是 --all ):

[mkoeppe@localhost sage]$ pkgs/sagemath-standard/.tox/sagepython-.../sage -t   \
                            -p4 --installed

这将针对文档测试进行测试,因为它们出现在已安装的文件副本中(在 site-packages/sage/... )。请注意,切勿编辑这些已安装的副本,因为它们可能会在没有警告的情况下被覆盖。

当测试不是sagemath标准的模块化分发包时,顶级模块 sage.all 不可用。使用选项 --environment 要选择适当的顶级模块,请执行以下操作:

[mkoeppe@localhost sage]$ pkgs/sagemath-categories/.tox/sagepython-.../sage -t \
                            -p4 --environment sage.all__sagemath_categories    \
                            --installed

要针对文档测试测试源代码树中显示的已安装模块,请执行以下操作 (src/sage/... ):

[mkoeppe@localhost sage]$ pkgs/sagemath-categories/.tox/sagepython-.../sage -t \
                            -p4 --environment sage.all__sagemath_categories    \
                            src/sage/structure

请注意,测试所有出现在源代码树中的文档测试没有意义,因为许多源文件可能没有安装在虚拟环境中。使用选项 --if-installed 跳过虚拟环境中未安装的所有Python/Cython模块的源文件:

[mkoeppe@localhost sage]$ pkgs/sagemath-categories/.tox/sagepython-.../sage -t \
                            -p4 --environment sage.all__sagemath_categories    \
                            --if-installed src/sage/schemes

此选项还可以与 --all **

[mkoeppe@localhost sage]$ pkgs/sagemath-categories/.tox/sagepython-.../sage -t \
                            -p4 --environment sage.all__sagemath_categories    \
                            --if-installed --all

最好的修复者

Sage提供了一个帮助更新文档测试的开发工具。

更新doctest输出

默认情况下, ./sage --fixdoctests 运行doctester,并将所有示例的预期输出替换为当前版本的Sage::

[mkoeppe@localhost sage]$ ./sage --fixdoctests \
                            --overwrite src/sage/arith/weird.py

例如,当应用于此Python文件时:

| r"""
| ...
|
| EXAMPLES::
|
|     sage: 2 + 2
|     5
|     sage: factor("91")
|     "7" * "13"
| ...

文档测试修复器按如下方式编辑文件:

| r"""
| ...
|
| EXAMPLES::
|
|     sage: 2 + 2
|     4
|     sage: factor("91")
|     Traceback (most recent call last):
|     ...
|     TypeError: unable to factor '91'
| ...

在此命令编辑源文件时,最好先使用 git commit 保存在文件中所做的任何更改。

在运行doctest修复程序之后,最好使用 git diff 检查自动化工具所做的所有编辑。

此工作流的替代方法是使用选项 --keep-both 。当一个示例的预期输出和实际输出不同时,它会复制该示例,并标记两个副本 # optional - EXPECTED# optional - GOT 。(因此,当重新运行doctester时,两个副本都不会运行;这使得 ./sage --fixdoctests 幂等元。)

当示例期望出现异常时,标准做法是使用 ... 。Doctest修复器在格式化实际输出时自动使用此缩写,如上面的示例所示。要禁用它以便可以检查异常的详细信息,请使用选项 --full-tracebacks 。这在结合使用时特别有用 --keep-both **

[mkoeppe@localhost sage]$ ./sage --fixdoctests --keep-both --full-tracebacks \
                            --overwrite src/sage/arith/weird.py

这将给出上述示例的以下结果:

| r"""
| ...
|
| EXAMPLES::
|
|     sage: 2 + 2                                 # optional - EXPECTED
|     5
|     sage: 2 + 2                                 # optional - GOT
|     4
|     sage: factor("91")                          # optional - EXPECTED
|     "7" * "13"
|     sage: factor("91")                          # optional - GOT
|     Traceback (most recent call last):
|     ...
|     File "<doctest...>", line 1, in <module>
|     factor("91")
|     File ".../src/sage/arith/misc.py", line 2680, in factor
|     raise TypeError("unable to factor {!r}".format(n))
|     TypeError: unable to factor '91'
| ...
| """

要确保更新所有文档测试,您可能必须使用选项 --long **

[mkoeppe@localhost sage]$ ./sage --fixdoctests --long \
                            --overwrite src/sage/arith/weird.py

如果您对允许此工具编辑源文件感到不舒服,可以使用选项 --no-overwrite ,这将创建一个扩展名为 .fixed 不是覆盖源文件::

[mkoeppe@localhost sage]$ ./sage --fixdoctests \
                            --no-overwrite src/sage/arith/weird.py

管理 # optional# needs 标签

当文件使用 # sage.doctest: optional/needs FEATURE 指令,doctest修复器会自动删除多余的 # optional/needs FEATURE 标签来自所有 sage: 台词。同样,当块范围内的标记 sage: # optional/needs FEATURE ,则doctest修复器从该作用域中的所有doctest中删除多余的标记。例如::

| # sage.doctest: optional - sirocco, needs sage.rings.number_field
| r"""
| ...
|
| EXAMPLES::
|
|     sage: # needs sage.modules sage.rings.number_field
|     sage: Q5 = QuadraticField(5)
|     sage: V = Q5^42                                 # needs sage.modules
|     sage: T = transmogrify(V)           # optional - bliss sirocco

会自动转换为:

| # sage.doctest: optional - sirocco, needs sage.rings.number_field
| r"""
| ...
|
| EXAMPLES::
|
|     sage: # needs sage.modules
|     sage: Q5 = QuadraticField(5)
|     sage: V = Q5^42
|     sage: T = transmogrify(V)               # optional - bliss

Doctest修复器还将 # optional/needs FEATURE 单个文档测试上的标签位于一组固定的制表位。

当出现以下情况时,文档测试员可能会发出样式警告 # optional/needs 标记在整个doctest块上重复,建议改用块范围的标记。Doctest修复程序会自动进行这些更改。

在某些情况下,文档测试员和文档测试修复者表现出太多的克制,而人工干预会改进文档测试的格式。在下面的示例中,doctester不会发出样式警告,因为第一个doctest行没有携带 # needs 标签::

| EXAMPLES::
|
|     sage: set_verbose(-1)
|     sage: P.<x,y,z> = ProjectiveSpace(QQbar, 2)     # needs sage.rings.number_field
|     sage: C = Curve([x^3*y + 2*x^2*y^2 + x*y^3      # needs sage.rings.number_field
|     ....:             + x^3*z + 7*x^2*y*z
|     ....:             + 14*x*y^2*z + 9*y^3*z], P)
|     sage: Q = P([0,0,1])                            # needs sage.rings.number_field
|     sage: C.tangents(Q)                             # needs sage.rings.number_field
|     [x + 4.147899035704788?*y,
|      x + (1.426050482147607? + 0.3689894074818041?*I)*y,
|      x + (1.426050482147607? - 0.3689894074818041?*I)*y]

要更改此示例,有两种方法:

  1. 只需添加一行 sage: # needs sage.rings.number_field 并运行doctest修复程序,这将删除各个doctest上的标记,这些标记现在已经变得多余。

  2. 在第一个doctest行之后插入空行,将块一分为二。现在 # needs 标记在整个第二个块上重复,因此运行doctest修复程序将添加一个块范围的标记并删除各个标记::

    | EXAMPLES::
    |
    |     sage: set_verbose(-1)
    |
    |     sage: # needs sage.rings.number_field
    |     sage: P.<x,y,z> = ProjectiveSpace(QQbar, 2)
    |     sage: C = Curve([x^3*y + 2*x^2*y^2 + x*y^3
    |     ....:             + x^3*z + 7*x^2*y*z
    |     ....:             + 14*x*y^2*z + 9*y^3*z], P)
    |     sage: Q = P([0,0,1])
    |     sage: C.tangents(Q)
    |     [x + 4.147899035704788?*y,
    |      x + (1.426050482147607? + 0.3689894074818041?*I)*y,
    |      x + (1.426050482147607? - 0.3689894074818041?*I)*y]
    

在文档测试员发出文档测试数据流警告的地方 (Variable ... referenced here was set only in doctest marked '# optional - FEATURE' )时,doctest修复器会自动添加丢失的 # optional/needs 标签。

有时,代码更改会使现有的 # optional/needs FEATURE 不必要的标签。在安装或虚拟环境中 FEATURE 不可用,则可以使用选项调用doctest修复程序 --probe FEATURE 。然后,它将运行标记为 # optional/needs - FEATURE 静默执行,如果该示例仍然有效,则该标记将自动删除。

备注

当文档字符串中的文档测试不对不同的值重复使用相同的变量时,探测效果最好。

让医生来处理 # optional/needs 标记,但不更改示例的预期结果,请使用选项 --only-tags 。此模式适用于大多数情况下对许多文件执行无人值守运行。

使用该选项 --verbose ,文档测试修复程序逐一显示文档测试人员的消息,并报告所做的更改。

警告

而doctest修复器保证保留之前出现的任何注释 # optional/needs 和表单的所有带括号的注释 # optional - FEATURE (EXPLANATION) ,则可能与doctest标签混合的任何自由格式注释都将丢失。

如果不想更新任何文档测试,可以使用选项 --no-test 。在此模式下,doctest修复器不运行doctester,而只正常化 # optional 标签。

在虚拟环境中使用

Doctest修复程序还可以使用安装在虚拟环境中的Sage doctester运行测试:

[mkoeppe@localhost sage]$ ./sage --fixdoctests --overwrite                      \
                            --distribution sagemath-categories                  \
                            src/sage/geometry/schemes/generic/*.py

此命令使用 --distribution 等效于使用更具体选项的命令 --venv--environment **

[mkoeppe@localhost sage]$ ./sage --fixdoctests --overwrite                      \
                            --venv pkgs/sagemath-categories/.tox/sagepython-... \
                            --environment sage.all__sagemath_categories
                            src/sage/geometry/schemes/generic/*.py

无论哪种方式,选项都是 --keep-both--full-tracebacks ,以及 --if-installed 都是隐含的。

在该操作模式中,当文档测试者在其虚拟环境中遇到未知的全局名称时 (NameError ),doctest修复程序将在其自己的环境(通常是完全安装的Sage库)中查找该名称,并添加一个 # needs ... 标记到文档测试。

同样,当博士生遇到 ModuleNotFoundError ,那么doctest修复器将自动添加一个 # needs ... 标签。

交换机 --distribution 可以重复;给定的分布将按顺序进行测试。vbl.使用 --distribution all 相当于一个预设列表 --distribution 开关。使用交换机 --fixed-point ,那么doctest修复程序将运行给定的发行版,直到不再进行任何更改。

更新基线文件

模块化的配送包 pkgs/sagemath-categoriespkgs/sagemath-repl 包含文件 known-test-failures*.json 与选件一起使用 --baseline-stats-path ,请参阅部分 辅助档案

在运行发行版的doctester之后,例如,通过 sage --fixdoctests ,您可以使用中存储的测试结果 timings2.json 文件以更新 known-test-failures*.json 档案。可以使用以下命令完成此更新::

[mkoeppe@localhost sage]$ ./sage --fixdoctests --no-test                        \
                            --update-known-test-failures --distribution all