예시: 단순 검증
예시: 단순 검증 (Example: Simple Validation)
결정적 검사로 단순한 텍스트 변환 함수를 평가하는 개념 증명 예시예요.
출처: 문서
본문
시나리오
텍스트를 타이틀 케이스로 변환하는 함수를 테스트하고 있어요. 다음을 검증하고 싶어요:
- 출력이 항상 문자열인지
- 출력이 기대 형식과 일치하는지
- 함수가 엣지 케이스를 올바르게 처리하는지
- 성능이 요구사항을 충족하는지
완전한 예시
from pydantic_evals import Case, Dataset
from pydantic_evals.evaluators import (
Contains,
EqualsExpected,
IsInstance,
MaxDuration,
)
# 테스트 중인 함수
def to_title_case(text: str) -> str:
"""Convert text to title case."""
return text.title()
# 평가 데이터셋 만들기
dataset = Dataset(
name='title_case_validation',
cases=[
# 기본 기능
Case(
name='basic_lowercase',
inputs='hello world',
expected_output='Hello World',
),
Case(
name='basic_uppercase',
inputs='HELLO WORLD',
expected_output='Hello World',
),
Case(
name='mixed_case',
inputs='HeLLo WoRLd',
expected_output='Hello World',
),
# 엣지 케이스
Case(
name='empty_string',
inputs='',
expected_output='',
),
Case(
name='single_word',
inputs='hello',
expected_output='Hello',
),
Case(
name='with_punctuation',
inputs='hello, world!',
expected_output='Hello, World!',
),
Case(
name='with_numbers',
inputs='hello 123 world',
expected_output='Hello 123 World',
),
Case(
name='apostrophes',
inputs="don't stop believin'",
expected_output="Don'T Stop Believin'",
),
],
evaluators=[
# 항상 문자열 반환
IsInstance(type_name='str'),
# 기대 출력과 일치
EqualsExpected(),
# 출력에 대문자가 포함되어야 함
Contains(value='H', evaluation_name='has_capitals'),
# 빨라야 함 (1ms 미만)
MaxDuration(seconds=0.001),
],
)
# 평가 실행
if __name__ == '__main__':
report = dataset.evaluate_sync(to_title_case)
# 결과 출력
report.print(include_input=True, include_output=True)
"""
Evaluation Summary: to_title_case
┏━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━┓
┃ Case ID ┃ Inputs ┃ Outputs ┃ Assertions ┃ Duration ┃
┡━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━┩
│ basic_lowercase │ hello world │ Hello World │ ✔✔✔✗ │ 10ms │
├──────────────────┼──────────────────────┼──────────────────────┼────────────┼──────────┤
│ basic_uppercase │ HELLO WORLD │ Hello World │ ✔✔✔✗ │ 10ms │
├──────────────────┼──────────────────────┼──────────────────────┼────────────┼──────────┤
│ mixed_case │ HeLLo WoRLd │ Hello World │ ✔✔✔✗ │ 10ms │
├──────────────────┼──────────────────────┼──────────────────────┼────────────┼──────────┤
│ empty_string │ - │ - │ ✔✔✗✗ │ 10ms │
├──────────────────┼──────────────────────┼──────────────────────┼────────────┼──────────┤
│ single_word │ hello │ Hello │ ✔✔✔✗ │ 10ms │
├──────────────────┼──────────────────────┼──────────────────────┼────────────┼──────────┤
│ with_punctuation │ hello, world! │ Hello, World! │ ✔✔✔✗ │ 10ms │
├──────────────────┼──────────────────────┼──────────────────────┼────────────┼──────────┤
│ with_numbers │ hello 123 world │ Hello 123 World │ ✔✔✔✗ │ 10ms │
├──────────────────┼──────────────────────┼──────────────────────┼────────────┼──────────┤
│ apostrophes │ don't stop believin' │ Don'T Stop Believin' │ ✔✔✗✗ │ 10ms │
├──────────────────┼──────────────────────┼──────────────────────┼────────────┼──────────┤
│ Averages │ │ │ 68.8% ✔ │ 10ms │
└──────────────────┴──────────────────────┴──────────────────────┴────────────┴──────────┘
"""
# 모두 통과했는지 확인
avg = report.averages()
if avg and avg.assertions == 1.0:
print('\n✅ All tests passed!')
else:
print(f'\n❌ Some tests failed (pass rate: {avg.assertions:.1%})')
"""
❌ Some tests failed (pass rate: 68.8%)
"""
기대 출력
Evaluation Summary: to_title_case
┏━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━┓
┃ Case ID ┃ Inputs ┃ Outputs ┃ Assertions ┃ Duration ┃
┡━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━┩
│ basic_lowercase │ hello world │ Hello World │ ✔✔✔✔ │ <1ms│
├───────────────────┼──────────────────────┼───────────────────────┼────────────┼──────────┤
│ basic_uppercase │ HELLO WORLD │ Hello World │ ✔✔✔✔ │ <1ms│
├───────────────────┼──────────────────────┼───────────────────────┼────────────┼──────────┤
│ mixed_case │ HeLLo WoRLd │ Hello World │ ✔✔✔✔ │ <1ms│
├───────────────────┼──────────────────────┼───────────────────────┼────────────┼──────────┤
│ empty_string │ │ │ ✔✔✗✔ │ <1ms│
├───────────────────┼──────────────────────┼───────────────────────┼────────────┼──────────┤
│ single_word │ hello │ Hello │ ✔✔✔✔ │ <1ms│
├───────────────────┼──────────────────────┼───────────────────────┼────────────┼──────────┤
│ with_punctuation │ hello, world! │ Hello, World! │ ✔✔✔✔ │ <1ms│
├───────────────────┼──────────────────────┼───────────────────────┼────────────┼──────────┤
│ with_numbers │ hello 123 world │ Hello 123 World │ ✔✔✔✔ │ <1ms│
├───────────────────┼──────────────────────┼───────────────────────┼────────────┼──────────┤
│ apostrophes │ don't stop believin' │ Don'T Stop Believin' │ ✔✔✔✔ │ <1ms│
├───────────────────┼──────────────────────┼───────────────────────┼────────────┼──────────┤
│ Averages │ │ │ 96.9% ✔ │ <1ms│
└───────────────────┴──────────────────────┴───────────────────────┴────────────┴──────────┘
✅ All tests passed!
참고: empty_string 케이스는 판정 하나가 실패했어요 (has_capitals). 빈 문자열에는 대문자가 없으니까요.
저장하고 불러오기
나중에 사용하기 위해 데이터셋을 저장해요:
from typing import Any
from pydantic_evals import Case, Dataset
from pydantic_evals.evaluators import EqualsExpected
# 테스트 중인 함수
def to_title_case(text: str) -> str:
"""Convert text to title case."""
return text.title()
# 데이터셋 만들기
dataset: Dataset[str, str, Any] = Dataset(
name='title_case_tests',
cases=[Case(inputs='test', expected_output='Test')],
evaluators=[EqualsExpected()],
)
# YAML로 저장
dataset.to_file('title_case_tests.yaml')
# 나중에 불러오기
dataset = Dataset.from_file('title_case_tests.yaml')
report = dataset.evaluate_sync(to_title_case)
케이스 더 추가하기
버그나 엣지 케이스를 발견하면 데이터셋에 추가해요:
from pydantic_evals import Dataset
# 기존 데이터셋 불러오기
dataset = Dataset.from_file('title_case_tests.yaml')
# 유니코드 버그 발견
dataset.add_case(
name='unicode_chars',
inputs='café résumé',
expected_output='Café Résumé',
)
# 대문자 단어 버그 발견
dataset.add_case(
name='acronyms',
inputs='the USA and FBI',
expected_output='The Usa And Fbi', # Python의 title() 동작
)
# 매우 긴 입력 테스트
dataset.add_case(
name='long_input',
inputs=' '.join(['word'] * 1000),
expected_output=' '.join(['Word'] * 1000),
)
# 업데이트된 데이터셋 저장
dataset.to_file('title_case_tests.yaml')
pytest와 함께 사용하기
CI/CD를 위해 pytest와 통합해요:
import pytest
from pydantic_evals import Dataset
# 테스트 중인 함수
def to_title_case(text: str) -> str:
"""Convert text to title case."""
return text.title()
@pytest.fixture
def title_case_dataset():
return Dataset.from_file('title_case_tests.yaml')
def test_title_case_evaluation(title_case_dataset):
"""Run evaluation tests."""
report = title_case_dataset.evaluate_sync(to_title_case)
# 모든 케이스가 통과해야 함
avg = report.averages()
assert avg is not None
assert avg.assertions == 1.0, f'Some tests failed (pass rate: {avg.assertions:.1%})'
def test_title_case_performance(title_case_dataset):
"""Verify performance."""
report = title_case_dataset.evaluate_sync(to_title_case)
# 모든 케이스가 빨리 완료되어야 함
for case in report.cases:
assert case.task_duration < 0.001, f'{case.name} took {case.task_duration}s'
다음 단계
더 알아보기 (Learn more)
- Pydantic Evals 문서: 예시: 단순 검증