Testing (Pytest)¶
BetterPy's largest feature group — 29 features that supercharge your pytest workflow with fixture management, fixture inspections, parametrize helpers, mocking support, assertions, and test tree navigation.
Fixtures¶
BetterPy provides first-class, deep integration for pytest fixtures, refactorings, inspections, and documentation directly inside the IDE.
Start with fixture-aware pytest support for a release-oriented overview of everything the shared fixture engine adds over plain PyCharm: pytest-style resolution, plugin fixtures, dynamic fixture strings, fixture typing, rename, Find Usages, and fixture-specific inspections.
Fixture Editor Integration¶
Enables deep integration of pytest fixtures into the IDE editor, making fixture names behave like normal Python symbols. BetterPy resolves fixture definitions with pytest-style precedence, then uses that model for navigation, completion, definition searches, hierarchy actions, renaming, and usages.
For the broader release overview of the shared fixture model, plugin support, dynamic fixture strings, typing, and inspections, see fixture-aware pytest support.
Navigation¶
Fixture parameters resolve to the fixture definition that pytest would choose for that location.
# tests/conftest.py
@pytest.fixture
def user():
return User("default")
# tests/api/conftest.py
@pytest.fixture
def user():
return User("api")
# tests/api/test_users.py
def test_profile(user):
assert user.name == "api"
In test_profile, Go to Declaration (⌘B / Ctrl+B) on user navigates to tests/api/conftest.py.
Completion¶
Fixture-name completion is available in test and fixture parameter lists. Suggestions include visible fixtures from the current file, imports, ancestor conftest.py files, and discovered plugin fixtures.
Completion can suggest client and inserts it as a normal parameter. BetterPy skips names that are already controlled by @pytest.mark.parametrize, and it keeps self and cls out of fixture suggestions.
Rename And Usages¶
Renaming a fixture updates fixture parameters and known fixture references rather than only the Python function declaration. Find Usages (⌥F7 / Alt+F7) also treats fixture injections as usages, so a fixture can be audited before changing or deleting it.
@pytest.fixture
def api_client():
return Client()
def test_status(api_client):
assert api_client.get("/status").ok
Renaming api_client updates both the fixture definition and the injected parameter.
Override Hierarchy Support¶
Fixture definitions participate in IDE hierarchy workflows:
- Go to Super from an overriding fixture opens the fixture it shadows in a broader scope.
- Gutter markers on overridden fixtures list narrower-scope fixtures that override them.
- Go to Type Declaration from a fixture parameter opens the fixture function that supplies the value.
- Implement/Override Methods can offer fixture overrides when editing test classes that inherit fixture methods.
Fixture Injection Intentions¶
Provides intentions to easily convert between explicit fixture parameters and @pytest.mark.usefixtures decorators.
Convert Between Parameter And Decorator Injection¶
Two intentions help switch between explicit fixture parameters and @pytest.mark.usefixtures.
Use the decorator form when a fixture is needed only for setup or teardown side effects. Use the parameter form when the test reads the fixture value.
Pytest fixture documentation¶
Enhances Quick Documentation and member type inference for pytest fixtures across files.
Quick Documentation on a fixture or fixture parameter shows the resolved fixture type, dataclass/Pydantic/TypedDict fields, attribute docstrings, and literal values returned or yielded by simple fixtures. List, tuple, set, and dict literals are rendered across multiple lines so nested fixture data is easier to scan.
Supported fixture cases:
- Primitive return types such as
str,bool,list,dict,set,int, andfloat. - Generator-style fixtures annotated as
Generator[T, ...],Iterator[T],Iterable[T], and their async variants; BetterPy documents and infers the yielded value typeT. - Dataclasses, Pydantic models, and TypedDicts, including inherited fields, default values, and attribute docstrings.
- Fixtures defined in
conftest.py, including fixtures whose returned class is declared inside the fixture body. - The built-in
requestfixture, which is typed as_pytest.fixtures.SubRequestwhen available.
Parametrized test arguments are ignored because they shadow fixtures with the same name.
How to invoke: F1 / Ctrl+Q on a fixture parameter.
Example:
import pytest
@pytest.fixture
def api_config() -> dict:
return {
"base_url": "https://api.example.test",
"headers": {"Accept": "application/json"},
"timeouts": [1, 5, 10],
}
def test_client(api_config):
...
Quick Documentation shows the fixture type and the returned dictionary value as a multiline block, including nested dictionaries and lists.
New pytest members¶
New pytest members adds Generate menu actions for creating pytest tests and fixtures in the current scope.
How to use it¶
Open a module or class matching the configured pytest collection naming, then run Generate | pytest test or Generate | pytest fixture.
When it helps¶
Use these actions when adding tests or fixtures near the caret without manually typing boilerplate or decorators.
Notes¶
- New test names and fixture names are generated uniquely for the current file or class.
- Fixture generation imports
pytestwhen needed. - Test and fixture generation are hidden when neither the current module nor the containing class matches the configured pytest collection naming.
- Test generation is hidden in
conftest.py, while fixture generation remains available there. - The feature is gated by the New pytest members setting under Settings | BetterPy | Testing (Pytest) | Fixtures.
Pytest hooks¶
Adds a Generate menu action for pytest hook stubs in conftest.py and go-to-declaration for hook functions.
How to invoke: ⌘N / Alt+Insert in conftest.py → "BetterPy: Pytest Hook"
Fixture Inspections¶
Pytest fixture scope inspection¶
Pytest fixture scope inspection reports fixtures whose scope is narrower than a fixture they depend on.
How to use it¶
Open a pytest fixture that depends on another fixture with a broader scope. BetterPy highlights incompatible scope declarations.
When it helps¶
Use this inspection to catch scope mismatches before pytest fails collection or runtime fixture setup.
Notes¶
- BetterPy can offer a quick fix for compatible scope adjustments.
- The feature is gated by the Pytest fixture scope inspection setting under Settings | BetterPy | Testing (Pytest) | Fixture Inspections.
Unused pytest fixture inspection¶
Unused pytest fixture inspection reports fixture functions that are not used by tests or other fixtures.
How to use it¶
Open a file containing pytest fixtures. BetterPy highlights fixtures that have no detected references.
When it helps¶
Use this inspection to remove dead fixture code and keep test support modules easier to navigate.
Notes¶
- BetterPy offers safe-delete for unused fixtures.
- The feature is gated by the Unused pytest fixture inspection setting under Settings | BetterPy | Testing (Pytest) | Fixture Inspections.
Pytest fixture direct import inspection¶
Pytest fixture direct import inspection reports fixture functions imported directly into conftest.py.
How to use it¶
Open a conftest.py file that imports fixture functions directly. BetterPy highlights imports that should be replaced with explicit plugin scoping.
When it helps¶
Use this inspection to keep fixture sharing explicit and avoid surprising fixture availability across test packages.
Notes¶
- Prefer
pytest_pluginswhen exposing fixtures from another module. - The feature is gated by the Pytest fixture direct import inspection setting under Settings | BetterPy | Testing (Pytest) | Fixture Inspections.
Fixture annotation mismatch inspection¶
Reports test or fixture parameters whose explicit type annotation does not match the value type provided by the resolved fixture.
Pytest fixture override contract inspection¶
Reports pytest fixture overrides whose produced value type is incompatible with the parent fixture they shadow.
Pytest redundant fixture import inspection¶
Reports explicitly imported pytest fixtures that are already auto-discoverable via conftest or plugins.
Examples¶
Redundant Import (Warning)¶
# conftest.py
import pytest
@pytest.fixture
def my_fixture():
return 42
# Warning: Fixture 'my_fixture' is already provided by pytest (conftest/plugins); the explicit import is redundant.
from conftest import my_fixture
def test_example(my_fixture):
assert my_fixture == 42
After Quick-Fix (Remove redundant fixture import)¶
request.param without params inspection¶
Reports fixtures that read request.param without declaring params= and without being targeted by indirect parametrization.
Unknown dynamic pytest fixture inspection¶
Reports unresolved string-based fixture requests in usefixtures, getfixturevalue, and indirect parametrization.
Pytest fixture uninjected reference inspection¶
Pytest fixture uninjected reference inspection reports fixture names referenced in a test or fixture without being declared as parameters.
How to use it¶
Open a pytest function that uses a fixture name directly without injecting it.
When it helps¶
Use this inspection to catch accidental global-looking fixture references that pytest will not inject automatically.
Notes¶
- BetterPy focuses on fixture functions and pytest test contexts.
- The feature is gated by the Pytest fixture uninjected reference inspection setting under Settings | BetterPy | Testing (Pytest) | Fixture Inspections.
@pytest.mark.usefixtures on fixture is a no-op inspection¶
@pytest.mark.usefixtures on fixture is a no-op inspection reports usefixtures decorators applied to fixture functions.
How to use it¶
Open a fixture function decorated with @pytest.mark.usefixtures(...). BetterPy highlights the decorator because pytest only applies it to tests.
When it helps¶
Use this inspection to find fixture setup assumptions that are silently ignored by pytest.
Notes¶
- Move the dependency into the fixture parameter list instead.
- The feature is gated by the @pytest.mark.usefixtures on fixture is a no-op inspection setting under Settings | BetterPy | Testing (Pytest) | Fixture Inspections.
pytest_plugins in non-root conftest inspection¶
pytest_plugins in non-root conftest inspection reports pytest_plugins assignments in non-root conftest.py files.
How to use it¶
Open a nested conftest.py file containing a pytest_plugins assignment. BetterPy highlights assignments that pytest will ignore.
When it helps¶
Use this inspection to move plugin declarations to the root conftest where pytest will honor them.
Notes¶
- BetterPy uses pytest configuration discovery to distinguish root and nested conftest files.
- The feature is gated by the pytest_plugins in non-root conftest inspection setting under Settings | BetterPy | Testing (Pytest) | Fixture Inspections.
Parametrize¶
Parametrize pytest test¶
Parametrize pytest test adds, removes, and maintains pytest.mark.parametrize parameters for pytest tests.
How to use it¶
Place the caret in a pytest test or parametrize decorator, then run the available BetterPy parametrize intention.
When it helps¶
Use these intentions when turning a single test into a parametrized test, adding another parameter to an existing decorator, removing an unused parameter, or renaming parametrized arguments safely.
Notes¶
- The feature includes rename validation for parametrized argument names.
- BetterPy keeps function parameters and decorator argnames synchronized.
- The feature is gated by the Parametrize pytest test setting under Settings | BetterPy | Testing (Pytest) | Parametrize.
Pytest parametrized case run gutter icon¶
This feature adds run gutter icons for individual pytest.mark.parametrize cases.
How to use it¶
Put each parametrized case on its own line, then use the gutter run icon beside the case to run only that pytest node.
Notes¶
- The line marker appears only when BetterPy can infer the exact pytest case ID.
- Explicit ids from
ids=[...]andpytest.param(..., id="...")are supported. - The feature is gated by the Pytest parametrized case run gutter icon setting under Settings | BetterPy | Testing (Pytest) | Parametrize.
Convert pytest.param¶
Convert pytest.param converts parametrized values between plain values and explicit pytest.param(...) calls.
How to use it¶
Place the caret inside a pytest.mark.parametrize values list, then run BetterPy: Convert argument to pytest.param() or the reverse conversion intention.
When it helps¶
Use this intention when adding or removing per-case metadata such as ids and marks while keeping the parameter value structure correct.
Notes¶
- BetterPy imports
pytestwhen converting plain values topytest.param(...). - Values with marks or ids are not converted back to plain values.
- The feature is gated by the Convert pytest.param setting under Settings | BetterPy | Testing (Pytest) | Parametrize.
Assertions & Test Editing¶
Use actual test outcome¶
Replaces assertion expected values with the actual value from the last failed test run.
How to invoke: ⌥⏎ / Alt+Enter on a failed assertion → "BetterPy: Use actual test outcome"
Toggle pytest skip¶
Toggle pytest skip adds or removes pytest skip markers for tests, test classes, modules, and parameter values.
How to use it¶
Place the caret on a supported pytest target, then run BetterPy: Toggle pytest skip from the intention menu.
When it helps¶
Use this intention when triaging tests and you need to skip or unskip the current target without editing decorators manually.
Notes¶
- The intention supports functions, classes, module-level
pytestmark,pytest.param(...), and simple parameter values in parametrized tests. - The feature is gated by the Toggle pytest skip setting under Settings | BetterPy | Testing (Pytest) | Assertions & Test Editing.
Surround with pytest.raises()¶
Surround with pytest.raises() wraps selected test statements in a with pytest.raises(Exception): block.
How to use it¶
Select one or more statements in a pytest test, then use the Python surround action and choose pytest.raises().
When it helps¶
Use this surrounder when converting a failing statement into an explicit exception assertion while keeping indentation and imports handled for you.
Notes¶
- BetterPy adds a
pytestimport when needed. - The surrounder is available only in pytest test functions and avoids wrapping code already inside
pytest.raises. - The feature is gated by the Surround with pytest.raises() setting under Settings | BetterPy | Testing (Pytest) | Assertions & Test Editing.
Pytest failed line inspection¶
Marks the line where a pytest test failed, providing visual feedback directly in the editor.
Notes¶
- The highlight is based on the last pytest failure location remembered by BetterPy.
- The feature works together with Use actual test outcome when an assertion diff is available.
- The feature is gated by the Pytest failed line inspection setting under Settings | BetterPy | Testing (Pytest) | Assertions & Test Editing.
Test Tree & Navigation¶
Copy pytest node IDs¶
Copy pytest node IDs copies pytest node identifiers for selected tests to the clipboard.
How to use it¶
Select one or more tests in the pytest test tree or pytest explorer, then run Copy Special | BetterPy: Copy Pytest Node IDs.
When it helps¶
Use this action when rerunning a specific test selection from a terminal, sharing an exact pytest target, or preparing command-line invocations.
Notes¶
- Multiple selected node IDs are copied one per line.
- The feature is gated by the Copy pytest node IDs setting under Settings | BetterPy | Testing (Pytest) | Test Tree & Navigation.
Copy pytest node ID from editor¶
Copy pytest node ID from editor copies the pytest node ID for the test at the caret.
How to use it¶
Place the caret inside a pytest test function, then run BetterPy: Copy Pytest Node ID from Copy Special.
When it helps¶
Use this action when you want to rerun the current test from a terminal or share an exact pytest target without opening the test tree.
Notes¶
- The action is available only inside pytest test functions.
- The feature is gated by the Copy pytest node ID from editor setting under Settings | BetterPy | Testing (Pytest) | Test Tree & Navigation.
Jump to pytest node in test tree¶
Jump to pytest node in test tree selects the matching node in the active pytest test tree for the test at the editor caret.
How to use it¶
Place the caret inside a pytest test function or class, then run BetterPy: Jump to Test Tree Node from the editor context menu or intention list.
When it helps¶
Use this feature after a pytest run when the editor is focused but you want to inspect the matching result node, failure state, or surrounding suite in the test tree.
Notes¶
- The action is available only when there is an active non-empty test tree.
- The feature is gated by the Jump to pytest node in test tree setting under Settings | BetterPy | Testing (Pytest) | Test Tree & Navigation.
Toggle pytest skip from test tree¶
Toggle pytest skip from test tree adds or removes @pytest.mark.skip for selected pytest nodes.
How to use it¶
Select a pytest function, class, module, or pytest explorer entry, then run BetterPy: Toggle Pytest Skip from the context menu.
When it helps¶
Use this action when triaging failures from the test results view and you want to skip or unskip the affected test without navigating manually through the project tree.
Notes¶
- Function selections toggle the marker on that function.
- Class and module selections toggle the marker at the matching scope.
- The feature is gated by the Toggle pytest skip from test tree setting under Settings | BetterPy | Testing (Pytest) | Test Tree & Navigation.
Run pytest with debug logging¶
Run pytest with debug logging duplicates the selected pytest run configuration, adds DEBUG CLI logging, and runs the selected pytest node.
How to use it¶
Select a pytest node in the test tree, then run BetterPy: Run Pytest with DEBUG logging from the test tree context menu.
When it helps¶
Use this action when a failing test needs extra pytest log output but you do not want to permanently change the original run configuration.
Notes¶
- The duplicated configuration is temporary.
- The duplicated configuration is narrowed to the selected test tree node (the pytest node id is targeted directly), so only that node runs.
- BetterPy appends
--log-cli-level=DEBUGwhen it is not already present. - The feature is gated by the Run pytest with debug logging setting under Settings | BetterPy | Testing (Pytest) | Test Tree & Navigation.
Pytest identifier in Search Everywhere¶
This Search Everywhere contributor finds pytest node identifiers directly from the IDE search popup.
How to use it¶
Open Search Everywhere and type a pytest node id or identifier fragment.
Notes¶
- Results navigate to the matching Python PSI element.
- The feature is gated by the Pytest identifier Search Everywhere setting.