pytest의 AST 단언 재작성

"AST 단언 재작성 메커니즘"

Pytest는 assert result == expected와 같은 코드가 실행되기 전에 구문 분석 트리(AST)를 통해 코드를 재구성합니다. 이 과정에서 단순한 비교 연산을 넘어, result와 expected의 속성값, 변수값을 모두 추적하여 상세한 오류 정보를 생성합니다. 이것이 바로 Pytest가 실패 시 풍부한 디버깅 정보를 제공하는 근본 원리입니다.

중요한 실수 방지 가이드

AST 재작성 기능은 특정 조건에서 비활성화됩니다. 단언문에 직접 메시지를 추가하면 재작성 과정이 중단되며, 기본 Python의 AssertionError로 대체됩니다.

# ❌ 오류 발생: 메시지 추가로 재작성이 무시됨
assert x == y, "x와 y가 동일하지 않음"

# ✅ 권장 방식: 자동 오류 분석 활성화
assert x == y

이 현상은 AST 노드의 구조적 해석 방식과 관련이 있습니다. assert 문은 내부적으로 test와 msg 두 개의 속성을 가지며, msg에 값이 할당되면 Pytest는 재작성 작업을 포기합니다.

AST 노드 구조 차이점

두 가지 작성 방식에 따라 생성되는 AST 노드는 다음과 같이 다릅니다:

  • 메시지 없는 단언:
assert x == y

→ AST 노드: {test: x == y, msg: None}

  • 메시지 있는 단언:
assert x == y, "x와 y가 동일하지 않음"

→ AST 노드: {test: x == y, msg: "x와 y가 동일하지 않음"}

Pytest의 내부 동작 로직

Pytest는 src/_pytest/assertion/rewrite.py 파일의 visit_Assert 메서드를 통해 다음 논리를 적용합니다:

def visit_Assert(self, node):
    if node.message is not None:
        # 사용자 정의 메시지가 존재하면
        return self.original_assert(node)
    else:
        # 메시지가 없으면
        return self.enhanced_assert(node)

이 결정 로직은 AST 노드의 msg 속성을 기반으로 작동하며, 사용자 메시지 유무에 따라 처리 방식을 완전히 다르게 합니다. msg 속성이 존재할 경우 Pytest는 사용자의 의도를 존중하기 위해 기본 assert 동작을 따르고, 그렇지 않으면 고급 오류 분석 기능을 활성화합니다.

핵심 개념 요약

Pytest는 AST 노드의 구조적 특성을 분석하여, 단언문에 사용자 메시지가 포함되어 있는지 정확하게 판별합니다. 이는 인간의 주석 해석과 달리, AST의 구조적 요소를 기반으로 한 정밀한 판단이며, 테스트 도구의 핵심 기능을 작동시키는 결정적 조건이 됩니다.

태그: Pytest AST assertion-rewriting Python-internals

8월 31일 10:23에 게시됨