# PhaseFieldX Unit Testing Framework: How to Add Tests with pytest

> Learn to add unit tests to PhaseFieldX using pytest. Create test files as test_*.py in the test directory and write test_* functions.

- Repository: [Miguel Castillón/phasefieldx](https://github.com/castillonmiguel/phasefieldx)
- Tags: how-to-guide
- Published: 2026-02-27

---

**PhaseFieldX uses pytest as its unit testing framework; you can add new tests by creating Python files matching `test_*.py` in the `test/` directory, writing functions that start with `test_`, and executing `pytest test/ --disable-warnings` locally or through the automated CI pipeline.**

The PhaseFieldX repository relies on pytest to maintain code quality and ensure reliability across its phase-field simulation codebase. Whether you are extending existing algorithms or adding new helper utilities, understanding the testing conventions allows you to contribute with confidence. This guide covers the exact file structure, naming conventions, and commands used in the `castillonmiguel/phasefieldx` repository.

## Testing Framework Overview

PhaseFieldX implements **pytest** as its sole unit testing framework. According to the source code, the project follows standard pytest discovery rules where test modules reside exclusively under the `test/` folder at the repository root. The GitHub Actions workflow in [`.github/workflows/testing.yml`](https://github.com/castillonmiguel/phasefieldx/blob/main/.github/workflows/testing.yml) executes the full suite with the command `pytest test/ --disable-warnings`, ensuring every pull request passes the complete test matrix before merging.

## Test Structure and Conventions

### File Naming Patterns

All test files must follow pytest discovery conventions. The repository accepts two patterns:
- Files prefixed with `test_` (e.g., [`test_file_utilities.py`](https://github.com/castillonmiguel/phasefieldx/blob/main/test_file_utilities.py))
- Files suffixed with `_test` (e.g., [`utilities_test.py`](https://github.com/castillonmiguel/phasefieldx/blob/main/utilities_test.py))

These modules live in the `test/` directory, as seen in [`test/test_file_utilities.py`](https://github.com/castillonmiguel/phasefieldx/blob/main/test/test_file_utilities.py), which imports `pytest` directly and validates file handling utilities.

### Test Function Requirements

Every test function must begin with the prefix `test_` to be recognized by pytest's test collector. The function should import the target code from the `phasefieldx` package and use standard `assert` statements for validation. No special decorators are required for basic functionality testing.

## How to Add New Tests to PhaseFieldX

### Writing a Basic Unit Test

Create a new file in `test/` following the `test_*.py` pattern. Import `pytest` and the specific function or class you want to validate from the main package, then write a function prefixed with `test_` that asserts expected behavior:

```python

# test/test_my_helper.py

import pytest
from phasefieldx import my_helper  # replace with the actual import

def test_my_helper_basic():
    """Check that my_helper returns the expected result for a simple case."""
    input_value = 10
    expected = 20           # replace with the real expected value

    assert my_helper(input_value) == expected

```

This structure works because the file location matches pytest's discovery pattern and the function name triggers automatic test execution during collection.

### Using Fixtures for Temporary Resources

For tests requiring file system operations or setup/teardown logic, leverage pytest's fixture system. The built-in `tmp_path` fixture provides isolated temporary directories without manual cleanup:

```python

# test/test_my_algorithm.py

import os
import pytest
from phasefieldx import run_algorithm

@pytest.fixture
def temp_dir(tmp_path):
    """Create a temporary working directory for the test."""
    return str(tmp_path)

def test_algorithm_writes_output(temp_dir):
    """Verify that the algorithm creates the expected output file."""
    run_algorithm(temp_dir)                 # call the function you want to test

    output_file = os.path.join(temp_dir, "result.txt")
    assert os.path.isfile(output_file)      # output file must exist

    # optionally check its contents

    with open(output_file) as f:
        assert "SUCCESS" in f.read()

```

The `temp_dir` fixture wraps `tmp_path` to provide a string path compatible with legacy file operations, ensuring your test runs in an isolated environment.

## Running Tests Locally and in CI

### Local Execution

Run the complete test suite from the repository root using the same command defined in the CI pipeline:

```bash

# Install the package first (required for imports)

pip install .

# Execute all tests

pytest test/ --disable-warnings

```

This command mirrors the automated testing defined in [`.github/workflows/testing.yml`](https://github.com/castillonmiguel/phasefieldx/blob/main/.github/workflows/testing.yml) at lines 40-45, ensuring consistency between local development and continuous integration environments.

### Continuous Integration

The repository automatically executes tests on every push and pull request. The workflow file [`.github/workflows/testing.yml`](https://github.com/castillonmiguel/phasefieldx/blob/main/.github/workflows/testing.yml) triggers `pytest test/ --disable-warnings` within a conda environment, validating code against the project's declared dependencies in [`pyproject.toml`](https://github.com/castillonmiguel/phasefieldx/blob/main/pyproject.toml). Any new test files added to the `test/` directory automatically join this execution queue without requiring workflow modifications.

## Summary

- **PhaseFieldX uses pytest**: The framework enforces naming conventions (`test_*.py` files, `test_*` functions) for automatic discovery.
- **Tests live in `test/`**: All test modules must reside in this root-level directory, as demonstrated by [`test/test_file_utilities.py`](https://github.com/castillonmiguel/phasefieldx/blob/main/test/test_file_utilities.py).
- **CI runs `pytest test/ --disable-warnings`**: This command, defined in [`.github/workflows/testing.yml`](https://github.com/castillonmiguel/phasefieldx/blob/main/.github/workflows/testing.yml), validates every contribution.
- **Add tests by creating files**: New test modules automatically integrate into both local runs and GitHub Actions workflows.

## Frequently Asked Questions

### What unit testing framework does PhaseFieldX use?

PhaseFieldX uses **pytest** as its unit testing framework. The source code in [`test/test_file_utilities.py`](https://github.com/castillonmiguel/phasefieldx/blob/main/test/test_file_utilities.py) explicitly imports `pytest`, and the CI pipeline in [`.github/workflows/testing.yml`](https://github.com/castillonmiguel/phasefieldx/blob/main/.github/workflows/testing.yml) executes the `pytest` command to run the entire suite.

### Where should I place new test files in the repository?

Place all new test files in the `test/` directory at the repository root. Name the file using the `test_*.py` pattern (e.g., [`test_new_feature.py`](https://github.com/castillonmiguel/phasefieldx/blob/main/test_new_feature.py)) so pytest's test collector discovers it automatically during execution.

### How do I run the PhaseFieldX tests on my local machine?

First install the package using `pip install .` from the repository root, then execute `pytest test/ --disable-warnings`. This command matches the CI configuration and runs all discovered tests while suppressing non-error warnings.

### Can I use pytest fixtures when adding tests to PhaseFieldX?

Yes, pytest fixtures are fully supported. You can use built-in fixtures like `tmp_path` for temporary directories or define custom fixtures within your test file for reusable setup logic, as shown in the `test_algorithm_writes_output` example above.