Anti-patterns to avoid

As you build out your test suite, there are some common mistakes that can reduce the effectiveness of your tests or make them harder to maintain. Here are some anti-patterns to watch out for.

Anti-PatternBetter Approach
Testing in productionUse staging or mock resources
No assertions beyond successUse output_for_node() to verify outputs
Ignoring test isolationEach test should be independent
Hardcoded test data pathsUse fixtures and relative paths
Skipping asset check testsTest checks like any other function

Testing in production

Never run tests against production systems unless you have a read-only, isolated subset. Production testing risks data corruption and may introduce unexpected costs.

Instead: Use mock resources for unit tests and staging/Docker environments for integration tests.

Only checking success

A test that only asserts result.success doesn't verify that your asset produced the correct output:

# Anti-pattern: Only checks that it ran
def test_my_asset():
    result = dg.materialize(assets=[my_asset])
    assert result.success  # This doesn't test the actual output!

Instead: Use output_for_node() to verify the asset produced the expected result:

# Better: Verify the actual output
def test_my_asset():
    result = dg.materialize(assets=[my_asset])
    assert result.success
    assert result.output_for_node("my_asset") == expected_data

Ignoring test isolation

Tests that depend on shared state or execution order are fragile and difficult to debug.

Instead: Each test should be completely independent. Use fixtures to set up test data and tear it down afterward.

Hardcoded paths

Hardcoding absolute paths makes tests fail when run on different machines or CI environments:

# Anti-pattern: Hardcoded path
def test_data_loading():
    data = load_data("/Users/john/project/data/test.csv")

Instead: Use relative paths or fixtures:

# Better: Use Path relative to the test file
from pathlib import Path

def test_data_loading():
    test_dir = Path(__file__).parent
    data = load_data(test_dir / "data/test.csv")

Skipping asset check tests

Asset checks contain validation logic that can have bugs just like any other code. Don't assume they work correctly just because they're "simple".

Instead: Test your asset checks with both passing and failing inputs:

def test_non_negative_check():
    # Test passing case
    result_pass = non_negative(10)
    assert result_pass.passed
    
    # Test failing case
    result_fail = non_negative(-10)
    assert not result_fail.passed

Summary

Writing good tests is as much about avoiding bad practices as it is about following good ones. Keep your tests focused, isolated, and thorough. When in doubt, ask yourself: "Would this test catch a real bug in my code?" If the answer is no, the test may need improvement.