每次测试后如何让Sphinx doctest重置Django数据库?

问题描述

[TL;DR] 使用 Sphinxmake doctest 时,测试中创建的 Django 模型会提交到数据库;我们如何防止它们自动提交或在每次测试之间重置数据库(使用类似于 pytest方法)?

设置

我使用脚本创建了一个基本的 Django 应用程序:

python -m pip install django sphinx pytest pytest-django pytest-sphinx
django-admin startproject project_name
cd project_name
mkdir project_name/app
python manage.py startapp app project_name/app
touch pytest.ini
touch conftest.py
mkdir docs
cd docs ; sphinx-quickstart ; cd ..

(在 sphinx-quickstart 中创建单独的源和构建目录。)

那么:

  1. project_name/app/models.py 更改为:
"""Models for the test application."""

from django.db import models


class Animal(models.Model):
    """A django model for an animal.
    
    .. rubric: Example
    
    .. testsetup:: animal
    
        from project_name.app.models import Animal

    .. testcode:: animal
    
        frog = Animal.objects.create(name="frog")
        print( frog )
    
    .. testoutput:: animal
    
        Animal object (1)
    """
    name = models.CharField(max_length=200)

  1. 修改project_name/settings.py 以将 'project_name.app' 添加INSTALLED_APPS
  2. 编辑 docs/source/conf.py 以在“路径设置”下添加行:
import os
import sys
import django

sys.path.insert(0,os.path.abspath('../..'))
os.environ['DJANGO_SETTINGS_MODULE'] = 'project_name.settings'
django.setup()

并在“常规配置”下设置:

extensions = [
  "sphinx.ext.autodoc","sphinx.ext.doctest",]
  1. docs/source/index.rst 替换为:
.. toctree::
   :maxdepth: 2
   :caption: Contents:

Project Name Documentation
==========================

.. currentmodule:: project_name.app.models

.. autoclass:: Animal
  1. pytest.ini 替换为:
[pytest]
DJANGO_SETTINGS_MODULE = project_name.settings
addopts = --doctest-modules
  1. conftest.py 替换为:
import pytest

@pytest.fixture(autouse=True)
def enable_db_access_for_all_tests(db):
    pass
  1. 然后运行:
python manage.py makemigrations
python manage.py migrate

问题

当我运行pytest时,文档中的测试每次都运行并通过;但是,当我使用 Sphinx 并在 make doctest 子目录中运行 docs 时,它第一次通过,然后在随后的时间失败,因为它每次都会创建一个新的 Animal 实例,并且将其提交到数据库,并且不会重新创建数据库

Running Sphinx v3.4.3
loading pickled environment... done
building [mo]: targets for 0 po files that are out of date
building [doctest]: targets for 1 source files that are out of date
updating environment: 0 added,0 changed,0 removed
looking for Now-outdated files... none found
running tests...

Document: index
---------------
**********************************************************************
File "../../project_name/app/models.py",line ?,in animal
Failed example:
    frog = Animal.objects.create(name="frog")
    print( frog )
Expected:
    Animal object (1)
Got:
    Animal object (2)
**********************************************************************

如何更改 docs/source/conf.py(或其他适当的脚本)以使用类似于 pytest方法,以便 Sphinx doctest 每次都通过(无需删除和重新创建数据库)?

(我不想更改文档中的单元测试;我想确保数据库已重置或数据未提交并在每次测试后回滚。)

解决方法

对此的快速(肮脏)解决方案是绕过该问题并在运行测试之前刷新数据库:

python ./manage.py migrate
python ./manage.py flush
./docs/make doctest
  • 首先应用迁移,以防测试 SQLite 数据库不存在;然后
  • 数据库已刷新(您可以使用 --no-input 标志跳过输入提示。但是,如果意外应用于生产数据库可能会很危险,因此默认情况下不包括在内);和
  • 最后,在空数据库上运行文档测试。

这在简单示例中有效,但如果运行多个示例创建同一模型的多个实例(并且每个实例将获得不同的自动生成的 id 值)并且测试处于非-确定性顺序。