Troubleshooting¶
This page covers common pitfalls and unexpected behaviors you may encounter when using Specter.
self is not an instance of my Spec class¶
Symptom: Accessing an attribute set on self inside before_all
fails in before_each, or calling super() raises a TypeError.
Cause: Specter executes each test suite under a state object that
mirrors your class hierarchy but is not literally an instance of your
Spec subclass. This is intentional: it prevents test-level attributes
from accidentally conflicting with Specter’s own infrastructure.
Calling super() from lifecycle hooks:
from specter import Spec
class BaseSpec(Spec):
def before_each(self):
self.client = create_client()
class MySpec(BaseSpec):
def before_each(self):
# self is the state object, not MySpec, so you must use type(self)
super(type(self), self).before_each()
self.extra = 'value'
See also: Test State and Inheritance
Tests in before_all / after_all don’t see each other’s state¶
Symptom: A value set on self inside before_all is not visible
in after_all, or vice versa.
Cause: The same state object issue as above. The state object is shared
within a single suite execution, so attributes set in before_all are
visible in test methods and after_all. If you’re not seeing them, double
check that you’re assigning to self (the state object) and not to a
local variable.
Parallel mode: state set in one test is not visible in another¶
Symptom: A value stored on self in one test is not available in
another test when running with --parallel.
Cause: This is by design. Parallel mode distributes tests across multiple
processes. Shared in-memory state between processes is not feasible without
explicit inter-process communication. Set up any shared state in
before_all, which runs in each process before its batch of tests.
Tests are not discovered¶
Symptom: specter runs but reports 0 tests.
Checklist:
Make sure your test files are inside the
spec/directory (or the path you passed to--search).Make sure each directory in the
spec/tree contains an__init__.pyfile so Python can import them.Check that your test class inherits from
SpecorDataSpecand is not decorated with@fixture.Check that your test methods do not start with
_and are not namedexecute,serialize,before_each,after_each,before_all, orafter_all.
A test passes even though an expect failed¶
Symptom: The console shows a failing expectation, but the test is marked as passing.
Cause: expect() failures are non-fatal: they are recorded against the
test case but do not raise an exception. A test case is only marked as
failed if at least one expect failed, or if an unhandled exception
occurred. If you believe the test should stop on failure, use require()
instead.
require() stops the test – subsequent expects don’t run¶
This is intentional. require() is a fatal assertion: as soon as it fails,
a FailedRequireException is raised internally and the test stops. Use
require() only for preconditions where running the rest of the test would
be meaningless or produce misleading errors.
Coverage is not reporting the right files¶
Configure .coveragerc to match your project layout. A minimal example:
[run]
source = mypackage
omit =
spec/*
*/vendor/*
Then run:
specter --coverage
xUnit output file is not created¶
Make sure you pass the path to the output file, not just a flag:
specter --xunit-results results/xunit.xml
If the directory does not exist, create it first. Specter will not create parent directories automatically.
Unicode characters appear garbled in CI output¶
Use --ascii-only to disable Unicode characters and color codes. This
replaces symbols like ∟ with plain ASCII equivalents and is safe for
environments that do not support UTF-8:
specter --ascii-only