MeWrite Docs

pytest: AssertionError

pytestでアサーションが失敗した場合のエラー

概要

pytestでテストのアサーションが失敗した場合に発生するエラーです。期待値と実際の値が一致しない場合に表示されます。

エラーメッセージ

FAILED tests/test_calculator.py::test_add - AssertionError: assert 4 == 5
E       assert 4 == 5
E        +  where 4 = add(2, 2)

原因

  1. ロジックの誤り: 実装が仕様と異なる
  2. テストの誤り: テストケースの期待値が間違っている
  3. データの問題: テストデータが不正
  4. 環境の違い: 環境依存のコード

解決策

1. 詳細なアサーション

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
def test_user_creation():
    user = create_user("John", "john@example.com")

    # 複数のアサーション
    assert user.name == "John"
    assert user.email == "john@example.com"
    assert user.is_active is True

    # オブジェクト全体の比較
    expected = User(name="John", email="john@example.com")
    assert user == expected

2. pytest.raises で例外テスト

1
2
3
4
5
6
7
8
9
import pytest

def test_division_by_zero():
    with pytest.raises(ZeroDivisionError):
        1 / 0

def test_custom_exception():
    with pytest.raises(ValueError, match="invalid value"):
        validate_input(-1)

3. フィクスチャの使用

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
import pytest

@pytest.fixture
def sample_user():
    return User(name="Test User", email="test@example.com")

@pytest.fixture
def db_session():
    session = create_session()
    yield session
    session.rollback()
    session.close()

def test_user_save(db_session, sample_user):
    db_session.add(sample_user)
    db_session.commit()
    assert db_session.query(User).count() == 1

4. パラメトライズ

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
import pytest

@pytest.mark.parametrize("input,expected", [
    (1, 1),
    (2, 4),
    (3, 9),
    (4, 16),
])
def test_square(input, expected):
    assert square(input) == expected

@pytest.mark.parametrize("a,b,expected", [
    (1, 2, 3),
    (0, 0, 0),
    (-1, 1, 0),
])
def test_add(a, b, expected):
    assert add(a, b) == expected

5. モックの使用

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
from unittest.mock import Mock, patch

def test_api_call():
    with patch('mymodule.requests.get') as mock_get:
        mock_get.return_value.json.return_value = {'id': 1}

        result = fetch_user(1)

        assert result['id'] == 1
        mock_get.assert_called_once_with('https://api.example.com/users/1')

@patch('mymodule.datetime')
def test_current_date(mock_datetime):
    mock_datetime.now.return_value = datetime(2025, 1, 1)
    assert get_today() == "2025-01-01"

6. 近似値の比較

1
2
3
4
5
6
7
8
9
import pytest

def test_float_calculation():
    result = 0.1 + 0.2
    assert result == pytest.approx(0.3)

def test_list_of_floats():
    result = [0.1 + 0.1, 0.2 + 0.2]
    assert result == pytest.approx([0.2, 0.4])

7. 非同期テスト

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
import pytest

@pytest.mark.asyncio
async def test_async_function():
    result = await async_fetch_data()
    assert result is not None

@pytest.mark.asyncio
async def test_async_with_timeout():
    async with asyncio.timeout(5):
        result = await slow_operation()
    assert result == "done"

8. テストのスキップ

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
import pytest
import sys

@pytest.mark.skip(reason="Not implemented yet")
def test_future_feature():
    pass

@pytest.mark.skipif(sys.platform == 'win32', reason="Linux only")
def test_linux_specific():
    pass

@pytest.mark.xfail(reason="Known bug #123")
def test_known_failure():
    assert broken_function() == "works"

9. conftest.py でフィクスチャ共有

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
# conftest.py
import pytest

@pytest.fixture(scope="session")
def database():
    db = create_database()
    yield db
    db.drop()

@pytest.fixture(autouse=True)
def reset_state():
    # 各テスト前に自動実行
    reset_global_state()
    yield
    # 各テスト後に自動実行
    cleanup()

10. デバッグ

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 失敗時にpdbを起動
pytest --pdb

# 最初の失敗で停止
pytest -x

# 最後に失敗したテストのみ再実行
pytest --lf

# 詳細な出力
pytest -v --tb=long

よくある間違い

  • assert と == の間にカンマを入れる(タプルになる)
  • フィクスチャのスコープを考慮していない
  • 非同期テストに @pytest.mark.asyncio を付け忘れる
  • モックのパスが間違っている(インポート元ではなく使用場所でパッチ)

最終更新: 2025-12-09