Testing
django-ca uses pytest for running the test suite:
$ pytest -v
This will generate a code coverage report in docs/build/html/.
Test coverage
The test suite must ensure 100% test coverage. Completely excluding code from test coverage is only allowed when absolutely necessary.
Conditional pragmas
In addition to the standard # pragma: no cover and # pragma: no branch, the test suite adds pragmas to
exclude code based on the Python version or library versions. For example:
if sys.version_info >= (3, 8): # pragma: only py>=3.8
from typing import Literal
else: # pragma: only py<3.8
from typing_extensions import Literal
If you have branches that are only relevant for some versions, there’s also pragmas for that:
if sys.version_info >= (3, 8): # pragma: py>=3.8 branch
print("Do something that's only useful in Python 3.8 or newer.")
if django.VERSION[:2] >= (3, 2): # pragma: django>=3.2 branch
print("Do something that's only useful in Django 3.2 or newer.")
You can use all operators (<, <=, ==, !=, >, >=), and we add pragma for the versions
of Python, Django, cryptography.
Please check ca/django_ca/tests/base/pragmas.py for a tested file that includes all supported pragmas.
Correctly using the pragmas is mandatory, as they are also used for finding outdated code when older versions
are deprecated.
pytest
Fixtures
Pytest fixtures used throughout the code base.
- django_ca.tests.base.fixtures.any_cert(request: SubRequest) str[source]
Parametrized fixture for absolutely any certificate name.
- django_ca.tests.base.fixtures.ca(request: SubRequest) CertificateAuthority[source]
Parametrized fixture for all certificate authorities known to the test suite.
- django_ca.tests.base.fixtures.ca_name(request: SubRequest) str[source]
Fixture for a name suitable for a CA.
- django_ca.tests.base.fixtures.certificate_policies(request: SubRequest, certificate_policies_value: CertificatePolicies) Extension[CertificatePolicies][source]
Parametrized fixture yielding different
x509.Extension[x509.CertificatePolicies]objects.
- django_ca.tests.base.fixtures.certificate_policies_value(request: SubRequest) CertificatePolicies[source]
Parametrized fixture with different
CertificatePoliciesobjects.
- django_ca.tests.base.fixtures.clear_cache() Iterator[None][source]
Fixture to clear the cache after the test.
- django_ca.tests.base.fixtures.ed_ca(request: SubRequest) CertificateAuthority[source]
Parametrized fixture for CAs with an Edwards-curve algorithm (ed448, ed25519).
- django_ca.tests.base.fixtures.hostname(ca_name: str) str[source]
Fixture for a hostname.
The value is unique for each test, and it includes the CA name, which includes the test name.
- django_ca.tests.base.fixtures.hsm_backend(request: SubRequest) Iterator[HSMBackend][source]
Fixture providing a HSMBackend with the current token and (randomized) passwords.
- django_ca.tests.base.fixtures.hsm_ocsp_backend(request: SubRequest) Iterator[HSMOCSPBackend][source]
Fixture providing a HSMBackend with the current token and (randomized) passwords.
- django_ca.tests.base.fixtures.interesting_cert(request: SubRequest) Certificate[source]
Parametrized fixture for “interesting” certificates.
A function using this fixture will be called once for each certificate with unusual extensions.
- django_ca.tests.base.fixtures.key_backend(request: SubRequest) StoragesBackend[source]
Return a
StoragesBackendfor creating a new CA.
- django_ca.tests.base.fixtures.precertificate_signed_certificate_timestamps_pub(request: SubRequest) Certificate[source]
Parametrized fixture for certificates that have a PrecertSignedCertificateTimestamps extension.
- django_ca.tests.base.fixtures.rfc4514_subject(subject: Name) str[source]
Fixture for an RFC 4514 formatted name to use for a subject.
The common name is based on
hostname()and identical tosubject().
- django_ca.tests.base.fixtures.root_ca_crl(root: CertificateAuthority) CertificateRevocationList[source]
Fixture for the user CRL object for the Root CA.
- django_ca.tests.base.fixtures.root_crl(root: CertificateAuthority) CertificateRevocationList[source]
Fixture for the global CRL object for the Root CA.
- django_ca.tests.base.fixtures.root_user_crl(root: CertificateAuthority) CertificateRevocationList[source]
Fixture for the user CRL object for the Root CA.
- django_ca.tests.base.fixtures.secondary_backend(request: SubRequest) StoragesBackend[source]
Return a
StoragesBackendfor the secondary key backend.
- django_ca.tests.base.fixtures.signed_certificate_timestamp_pub(request: SubRequest) Certificate[source]
Parametrized fixture for certificates that have any SCT extension.
- django_ca.tests.base.fixtures.signed_certificate_timestamps_pub(request: SubRequest) Certificate[source]
Parametrized fixture for certificates that have a SignedCertificateTimestamps extension.
Note
There are no certificates with this extension right now, so this fixture is in fact never run.
- django_ca.tests.base.fixtures.softhsm_setup(tmp_path: Path) Iterator[Path][source]
Fixture to set up a unique SoftHSM2 configuration.
- django_ca.tests.base.fixtures.softhsm_token(request: SubRequest, settings: SettingsWrapper) str[source]
Get a unique token for the current test.
- django_ca.tests.base.fixtures.subject(hostname: str) Name[source]
Fixture for a
Nameto use for a subject.The common name is based on
hostname()and identical torfc4514_subject().
- django_ca.tests.base.fixtures.tmpcadir(tmp_path: Path, settings: SettingsWrapper) Iterator[Path][source]
Fixture to create a temporary directory for storing files using the StoragesBackend.
- django_ca.tests.base.fixtures.usable_ca(request: SubRequest) CertificateAuthority[source]
Parametrized fixture for every usable CA (with usable private key).
- django_ca.tests.base.fixtures.usable_ca_name(request: SubRequest) CertificateAuthority[source]
Parametrized fixture for the name of every usable CA.
- django_ca.tests.base.fixtures.usable_ca_name_by_type(request: SubRequest) CertificateAuthority[source]
Parametrized fixture for the name of a CA of every type (
"dsa","root", …).
- django_ca.tests.base.fixtures.usable_cas(request: SubRequest) list[CertificateAuthority][source]
Fixture for all usable CAs as a list.
- django_ca.tests.base.fixtures.usable_cert(request: SubRequest) Certificate[source]
Parametrized fixture for every
{ca}-certcertificate.The name of the certificate can be retrieved from the non-standard test_name property of the certificate.
- django_ca.tests.base.fixtures.usable_hsm_ca(request: SubRequest, db: Literal[None]) CertificateAuthority[source]
Parametrized fixture yielding a certificate authority for every key type.
- django_ca.tests.base.fixtures.x448_private_key() X448PrivateKey[source]
Session fixture for an x448 private key.
Generated fixtures
- {name}_pub -
Certificate Certificate loaded from test fixture data.
Available for every CA generated in the test fixtures and every certificate. Examples:
root_pub,root_cert_pub,profile_server_pub. Contributed certificates are prefixed withcontrib_(see below).- {ca_name} -
CertificateAuthority Certificate authority model without usable private key files.
Available for every CA generated in the test fixtures. Using this fixture enables database access.
- {cert} -
Certificate Certificate model for certificates generated in test fixture data.
- contrib_{ca_name} -
CertificateAuthority Certificate authority model for a contributed certificate.
Examples:
contrib_geotrustandcontrib_startssl_class3.- contrib_{ca_name}_cert -
Certificate Certificate model for contributed certificates loaded from test fixture data.
Examples:
contrib_geotrust_certandcontrib_startssl_class3_cert.- contrib_{ca_name}_cert_pub -
Certificate Certificate for contributed certificates loaded from test fixture data.
Examples:
contrib_geotrust_cert_pubandcontrib_startssl_class3_cert_pub.- contrib_{ca_name}_pub -
Certificate Certificate for contributed certificate authorities loaded from test fixture data.
Examples:
contrib_geotrust_pubandcontrib_startssl_class3_pub.- usable_{ca_name} -
CertificateAuthority Certificate authority model with usable private key files.
Available for every CA generated in the test fixtures.
Mocks
Mocks used in the test suite.
- django_ca.tests.base.mocks.mock_celery_task(task: str, *calls: tuple[tuple[Any, ...], dict[str, Any]]) Iterator[MagicMock][source]
Context manager to mock celery invocations.
This context manager mocks
celery.app.task.Task.apply_async, the final function in celery before the message is passed to the handlers for the configured message transport (Redis, MQTT, …). The context manager will validate the mock was called as specified in calls.The context manager will also assert that the args and kwargs passed to the tasks are JSON serializable.
Warning
The args and kwargs passed to the task are the first and second argument passed to the mocked
apply_async. You must consider this when passing calls. For example:with self.mock_celery_task("django_ca.tasks.cache_crls", (((), {}), {})): cache_crls.delay() with self.mock_celery_task("django_ca.tasks.cache_crls", ((("foo"), {"key": "bar"}), {})): cache_crls.delay("foo", key="bar")
Assertions
django_ca.tests.base.assertions collects assertions used throughout the entire test suite.
- django_ca.tests.base.assertions.assert_authority_key_identifier(issuer: CertificateAuthority, cert: X509CertMixin) None[source]
Assert the AuthorityKeyIdentifier extension of issuer.
This assertion tests that
AuthorityKeyIdentifierextension of cert matches theSubjectKeyIdentifierextension of issuer.
- django_ca.tests.base.assertions.assert_ca_properties(ca: ~django_ca.models.CertificateAuthority, name: str, parent: ~django_ca.models.CertificateAuthority | None = None, private_key_type: type[~cryptography.hazmat.primitives.asymmetric.ed25519.Ed25519PrivateKey | ~cryptography.hazmat.primitives.asymmetric.ed448.Ed448PrivateKey | ~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey | ~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKey | ~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePrivateKey] = <class 'cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey'>, acme_enabled: bool = False, acme_profile: str | None = None, acme_requires_contact: bool = True, password: bytes | None = None) None[source]
Assert some basic properties of a CA.
- django_ca.tests.base.assertions.assert_certificate(cert: ~cryptography.hazmat.bindings._rust.x509.Certificate | ~django_ca.models.CertificateAuthority | ~django_ca.models.Certificate, subject: ~cryptography.x509.name.Name, algorithm: type[~cryptography.hazmat.primitives.hashes.HashAlgorithm] = <class 'cryptography.hazmat.primitives.hashes.SHA512'>, signer: ~django_ca.models.CertificateAuthority | ~cryptography.hazmat.bindings._rust.x509.Certificate | None = None) None[source]
Assert certificate properties.
- django_ca.tests.base.assertions.assert_command_error(msg: str, returncode: int = 1) Iterator[None][source]
Context manager asserting that CommandError is raised.
- Parameters:
- msgstr
The regex matching the exception message.
- django_ca.tests.base.assertions.assert_count_equal(first: Iterable[Any], second: Iterable[Any]) None[source]
Roughly equivalent version of
unittests assertCountEqual().
- django_ca.tests.base.assertions.assert_create_ca_signals(pre: bool = True, post: bool = True) Iterator[tuple[Mock, Mock]][source]
Context manager asserting that the pre_create_ca/post_create_ca signals are (not) called.
- django_ca.tests.base.assertions.assert_create_cert_signals(pre: bool = True, post: bool = True) Iterator[tuple[Mock, Mock]][source]
Context manager asserting that the pre_create_cert/post_create_cert signals are (not) called.
- django_ca.tests.base.assertions.assert_crl(crl: bytes | ~cryptography.hazmat.bindings._rust.x509.CertificateRevocationList, expected: ~typing.Sequence[~django_ca.models.X509CertMixin] | None = None, signer: ~django_ca.models.CertificateAuthority | None = None, expires: int = 86400, algorithm: ~cryptography.hazmat.primitives.hashes.HashAlgorithm | None = None, encoding: ~cryptography.hazmat.primitives._serialization.Encoding = <Encoding.PEM: 'PEM'>, idp: ~cryptography.x509.extensions.Extension[~cryptography.x509.extensions.IssuingDistributionPoint] | None = None, extensions: list[~cryptography.x509.extensions.Extension[~cryptography.x509.extensions.ExtensionType]] | None = None, crl_number: int = 0, entry_extensions: tuple[list[~cryptography.x509.extensions.Extension[~cryptography.x509.extensions.ExtensionType]]] | None = None, last_update: ~datetime.datetime | None = None) None[source]
Test the given CRL.
- Parameters:
- crlbytes
The raw CRL
- expectedlist
- signer
- expires
- algorithm
- encoding
- idp
- extensions
- crl_number
- django_ca.tests.base.assertions.assert_e2e_command_error(cmd: Sequence[str], stdout: str | bytes | Pattern = '', stderr: str | bytes | Pattern = '') None[source]
Assert that the passed command raises a CommandError with the given message.
- django_ca.tests.base.assertions.assert_e2e_error(cmd: Sequence[str], stdout: str | bytes | Pattern = '', stderr: str | bytes | Pattern = '', code: int = 2) None[source]
Assert an error was through in an e2e command.
- django_ca.tests.base.assertions.assert_extension_equal(first: Extension[ExtensionType] | None, second: Extension[ExtensionType] | None) None[source]
Compare two extensions for equality (or if both are None).
This assertion overrides comparison for iterable extension and should be used only when order of these extension values cannot be guaranteed. For example, two ExtendedKeyUsage extension will pass as equal regardless of order of the extended key usages in the extensions.
- django_ca.tests.base.assertions.assert_extensions(cert: X509CertMixin | Certificate, extensions: Iterable[Extension[ExtensionType]], signer: CertificateAuthority | None = None, expect_defaults: bool = True) None[source]
Assert that cert has the given extensions.
- django_ca.tests.base.assertions.assert_improperly_configured(msg: str | None) Iterator[None][source]
Shortcut for testing that the code raises ImproperlyConfigured with the given message.
- django_ca.tests.base.assertions.assert_issuing_distribution_point(extension: Extension[IssuingDistributionPoint], full_name: Iterable[GeneralName] | None = None, relative_name: RelativeDistinguishedName | None = None, only_contains_user_certs: bool = False, only_contains_ca_certs: bool = False, only_some_reasons: frozenset[ReasonFlags] | None = None, indirect_crl: bool = False, only_contains_attribute_certs: bool = False, critical: bool = True) None[source]
Shortcut for asserting an Issuing Point Distribution extension.
- django_ca.tests.base.assertions.assert_post_issue_cert(post: Mock, cert: Certificate) None[source]
Assert that the post_issue_cert signal was called with the expected certificate.
- django_ca.tests.base.assertions.assert_revoked(cert: X509CertMixin, reason: str | None = None, compromised: datetime | None = None) None[source]
Assert that the certificate is now revoked.
- django_ca.tests.base.assertions.assert_sign_cert_signals(pre: bool = True, post: bool = True) Iterator[tuple[Mock, Mock]][source]
Context manager mocking both
pre_create_caandpost_create_casignals.
- django_ca.tests.base.assertions.assert_signature(chain: Iterable[CertificateAuthority], cert: Certificate | CertificateAuthority) None[source]
Assert that cert is properly signed by chain.
- django_ca.tests.base.assertions.assert_system_exit(code: int) Iterator[None][source]
Assert that SystemExit is raised.
- django_ca.tests.base.assertions.assert_validation_error(errors: dict[str, list[str]]) Iterator[None][source]
Context manager to assert that a ValidationError is thrown.
Admin interface
django_ca.tests.admin.assertions collects assertions used when testing the admin interface.
- django_ca.tests.admin.assertions.assert_change_response(response: HttpResponse, media_css: tuple[tuple[str, str], ...] = ()) None[source]
Assert that the passed response is a model change view.
- django_ca.tests.admin.assertions.assert_changelist_response(response: HttpResponse, *objects: Model) None[source]
Assert that the passed response is a model
changelistview.
Utility functions
Utility functions used in testing.
- class django_ca.tests.base.utils.DummyBackend(alias: str, **kwargs: Any)[source]
Backend with no actions whatsoever.
- django_ca.tests.base.utils.authority_information_access(ca_issuers: Iterable[GeneralName] | None = None, ocsp: Iterable[GeneralName] | None = None, critical: bool = False) Extension[AuthorityInformationAccess][source]
Shortcut for getting a AuthorityInformationAccess extension.
- django_ca.tests.base.utils.basic_constraints(ca: bool = False, path_length: int | None = None, critical: bool = True) Extension[BasicConstraints][source]
Shortcut for getting a BasicConstraints extension.
- django_ca.tests.base.utils.certificate_policies(*policies: PolicyInformation, critical: bool = False) Extension[CertificatePolicies][source]
Shortcut for getting a Certificate Policy extension.
- django_ca.tests.base.utils.cmd(*args: Any, stdout: BytesIO, stderr: BytesIO, **kwargs: Any) tuple[bytes, bytes][source]
- django_ca.tests.base.utils.cmd(*args: Any, stdout: BytesIO, stderr: StringIO | None = None, **kwargs: Any) tuple[bytes, str]
- django_ca.tests.base.utils.cmd(*args: Any, stdout: StringIO | None = None, stderr: BytesIO, **kwargs: Any) tuple[str, bytes]
- django_ca.tests.base.utils.cmd(*args: Any, stdout: StringIO | None = None, stderr: StringIO | None = None, **kwargs: Any) tuple[str, str]
Call to a manage.py command using call_command.
- django_ca.tests.base.utils.cmd_e2e(args: Sequence[str], *, stdin: StringIO | bytes | None = None, stdout: StringIO | None = None, stderr: StringIO | None = None) tuple[str, str][source]
- django_ca.tests.base.utils.cmd_e2e(args: Sequence[str], *, stdin: StringIO | bytes | None = None, stdout: BytesIO, stderr: StringIO | None = None) tuple[bytes, str]
- django_ca.tests.base.utils.cmd_e2e(args: Sequence[str], *, stdin: StringIO | bytes | None = None, stdout: StringIO | None = None, stderr: BytesIO) tuple[str, bytes]
- django_ca.tests.base.utils.cmd_e2e(args: Sequence[str], *, stdin: StringIO | bytes | None = None, stdout: BytesIO, stderr: BytesIO) tuple[bytes, bytes]
Call a management command the way manage.py does.
Unlike call_command, this method also tests the argparse configuration of the called command.
- django_ca.tests.base.utils.cn(value: str) NameAttribute[str][source]
Shortcut for creating a common name attr.
- django_ca.tests.base.utils.country(value: str) NameAttribute[str][source]
Shortcut for creating a country attr.
- django_ca.tests.base.utils.crl_cache_key(serial: str, encoding: ~cryptography.hazmat.primitives._serialization.Encoding = <Encoding.DER: 'DER'>, only_contains_ca_certs: bool = False, only_contains_user_certs: bool = False, only_contains_attribute_certs: bool = False, only_some_reasons: ~collections.abc.Iterable[~cryptography.x509.extensions.ReasonFlags] | None = None) str[source]
Shortcut to get a CRL cache key.
- django_ca.tests.base.utils.crl_distribution_points(*distribution_points: DistributionPoint, critical: bool = False) Extension[CRLDistributionPoints][source]
Shortcut for getting a CRLDistributionPoint extension.
- django_ca.tests.base.utils.distribution_point(full_name: Iterable[GeneralName] | None = None, relative_name: RelativeDistinguishedName | None = None, reasons: frozenset[ReasonFlags] | None = None, crl_issuer: Iterable[GeneralName] | None = None) DistributionPoint[source]
Shortcut for generating a single distribution point.
- django_ca.tests.base.utils.dns(name: str) DNSName[source]
Shortcut to get a
cryptography.x509.DNSName.
- django_ca.tests.base.utils.extended_key_usage(*usages: ObjectIdentifier, critical: bool = False) Extension[ExtendedKeyUsage][source]
Shortcut for getting an ExtendedKeyUsage extension.
- django_ca.tests.base.utils.freshest_crl(*distribution_points: DistributionPoint, critical: bool = False) Extension[FreshestCRL][source]
Shortcut for getting a CRLDistributionPoints extension.
- django_ca.tests.base.utils.get_cert_context(name: str) dict[str, Any][source]
Get a dictionary suitable for testing output based on the dictionary in basic.certs.
- django_ca.tests.base.utils.get_idp(full_name: Iterable[GeneralName] | None = None, indirect_crl: bool = False, only_contains_attribute_certs: bool = False, only_contains_ca_certs: bool = False, only_contains_user_certs: bool = False, only_some_reasons: frozenset[ReasonFlags] | None = None, relative_name: RelativeDistinguishedName | None = None) Extension[IssuingDistributionPoint][source]
Get an IssuingDistributionPoint extension.
- django_ca.tests.base.utils.ip(name: IPv4Address | IPv6Address | IPv4Network | IPv6Network) IPAddress[source]
Shortcut to get a
cryptography.x509.IPAddress.
- django_ca.tests.base.utils.iso_format(value: datetime, timespec: str = 'seconds') str[source]
Convert a timestamp to ISO, with ‘Z’ instead of ‘+00:00’.
- django_ca.tests.base.utils.issuer_alternative_name(*names: GeneralName, critical: bool = False) Extension[IssuerAlternativeName][source]
Shortcut for getting a IssuerAlternativeName extension.
- django_ca.tests.base.utils.key_usage(**usages: bool) Extension[KeyUsage][source]
Shortcut for getting a KeyUsage extension.
- django_ca.tests.base.utils.mock_slug() Iterator[str][source]
Mock random slug generation, yields the static value.
- django_ca.tests.base.utils.name_constraints(permitted: Iterable[GeneralName] | None = None, excluded: Iterable[GeneralName] | None = None, critical: bool = True) Extension[NameConstraints][source]
Shortcut for getting a NameConstraints extension.
- django_ca.tests.base.utils.ocsp_no_check(critical: bool = False) Extension[OCSPNoCheck][source]
Shortcut for getting a OCSPNoCheck extension.
- class django_ca.tests.base.utils.override_tmpcadir(**kwargs)[source]
Sets the CA_DIR directory to a temporary directory.
- django_ca.tests.base.utils.precert_poison() Extension[PrecertPoison][source]
Shortcut for getting a PrecertPoison extension.
- django_ca.tests.base.utils.rdn(name: Iterable[tuple[ObjectIdentifier, str]]) RelativeDistinguishedName[source]
Shortcut to get a
cryptography.x509.RelativeDistinguishedName.
- django_ca.tests.base.utils.root_reverse(name: str, **kwargs: Any) str[source]
Shortcut to get a django-ca URI with a root serial.
- django_ca.tests.base.utils.root_uri(name: str, hostname: str | None = None, **kwargs: Any) str[source]
Full URI with a root serial.
- django_ca.tests.base.utils.state(value: str) NameAttribute[str][source]
Return a state name attr.
- django_ca.tests.base.utils.subject_alternative_name(*names: GeneralName, critical: bool = False) Extension[SubjectAlternativeName][source]
Shortcut for getting a SubjectAlternativeName extension.
- django_ca.tests.base.utils.subject_key_identifier(cert: X509CertMixin | Certificate) Extension[SubjectKeyIdentifier][source]
Shortcut for getting a SubjectKeyIdentifier extension.
- django_ca.tests.base.utils.tls_feature(*features: TLSFeatureType, critical: bool = False) Extension[TLSFeature][source]
Shortcut for getting a TLSFeature extension.
- django_ca.tests.base.utils.uri(url: str) UniformResourceIdentifier[source]
Shortcut to get a
cryptography.x509.UniformResourceIdentifier.
Doctests
django_ca.tests.base.doctest provides helper functions for testing doctests.
Functions in this module use a custom OutputChecker to enable the STRIP_WHITESPACE doctest option. This
option will remove all whitespace (including newlines) from the both actual and expected output. It can be
used for formatting actual output with newlines to improve readability. For example:
>>> from cryptography import x509
>>> from cryptography.x509.oid import ExtensionOID
>>> x509.Extension(
... oid=ExtensionOID.BASIC_CONSTRAINTS,
... critical=True,
... value=x509.BasicConstraints(ca=False, path_length=None)
... )
<Extension(
oid=<ObjectIdentifier(oid=2.5.29.19, name=basicConstraints)>,
critical=True,
value=<BasicConstraints(ca=False, path_length=None)>
)>
Use django_ca.tests.base.doctest.doctest_module() to test a Python module:
def test_doctests() -> None:
"""Run doctests for this module."""
failures, _tests = doctest_module("django_ca.pydantic.name")
assert failures == 0, f"{failures} doctests failed, see above for output."
Helper functions for doctests.
- django_ca.tests.base.doctest.doctest_module(module: str, name: str | None = None, globs: dict[str, str] | None = None, verbose: bool | None = False, report: bool = False, optionflags: int = 0, extraglobs: dict[str, str] | None = None, raise_on_error: bool = False, exclude_empty: bool = False) TestResults[source]
Shortcut for running doctests in the given Python module.
This function is based on
doctest.testmod(). It differs in that it will add theSTRIP_WHITESPACEdoctest option and interpret module as module path if astrand import the module. The report and verbose flags also default toFalse, as this provides cleaner output in modules with a lot of doctests.