pytest 에서 자동화를 구현하면서 필요해서 리서치했던 주요 builtin fixture에 대해 정리한 포스팅 입니다.
request.config.getoption("--명령어옵션") # 커맨드라인으로부터 받은 설정 값
request.config.getini("--명령어옵션") # ini 설정파일로부터 받은 설정 값
conftest.py
@pytest.fixture(scope="session")
def env(request):
return request.config.getoption("--env")
fixture 함수에서 request 객체를 사용하는 반면, hook 함수에서는 item 객체를 사용합니다.
item.config.getoption("명령어옵션") # 커맨드라인으로부터 받은 설정 값
item.config.getini("명령어옵션") # ini 설정파일로부터 받은 설정 값
conftest.py
@pytest.hookimpl(tryfirst=True, hookwrapper=True)
def pytest_runtest_makereport(item):
env = item.config.getoption("env")
config.cache
객체의 set()
, get()
함수를 사용하여 테스트함수 -> pytest로 변수를 받아올 수 있습니다.
request.config.cache.set('변수명', 값) # 테스트함수에서 사용
item.session.config.cache.get('변수명', 디폴트값) # conftest.py 에서 테스트함수로부터 변수 받아올 때 사용
아래 예시는 테스트 함수에서 구글 URL에 접근 후 구글 로고를 캡쳐하여 테스트 함수가 수행된 이후에 테스트 리포트를 출력하는 hook 함수에 전달하여 테스트 실패 시 locator를 캡쳐하여 HTML 리포트에 첨부할 수 있도록 하는 코드 입니다.(모든 과정을 담기에는 코드가 길어져 테스트 함수로부터 전달받은 capture_locator를 활용하는 부분만 넣었습니다.)
test_sample.py
def test_example():
request.config.cache.set('pytest_custom_info', [
{
'url': "https://www.google.com/"
'screenshot': True
'capture_locator': driver.find_element(By.CSS_SELECTOR, 'img[alt="Google"]')
}
])
conftest.py
@pytest.hookimpl(tryfirst=True, hookwrapper=True)
def pytest_runtest_makereport(item):
# ... 생략
pytest_custom_info = item.session.config.cache.get('pytest_custom_info', [])
if pytest_custom_info:
image_file = None
if capture_locator:
try:
capture_element = WebDriverWait(driver, 3).until(EC.visibility_of_element_located(capture_locator))
image_file = capture_element.screenshot('Screenshot.png')
with open(image_file, 'rb') as img:
embedded_image = str(base64.b64encode(img.read()).decode('utf-8))
except TimeoutException:
test_logger.error(msg=f'{driver_url}: Capture Element Screenshot: Failed to find locator: {capture_locator}')
if image_file:
plugin_extras.append(pytest_html.extras.image(embedded_image))
이전 pytest 수행 시의 값이 캐시되기 때문에, 캐시되지 않도록 하기 위해서는 pytest 명령어 옵션에 --cache-clear
를 추가해야 합니다.
반대로, pytest -> 테스트함수로 변수를 가져올 시에는 pytest_configure
hook 함수에서 정의된 pytest.변수명
을 사용할 수 있습니다.
기본적으로 fixture로 환경변수인 env를 선언해두면, 모든 테스트함수에서 env를 활용할 수 있으나 API 호출 횟수를 줄이기 위해 env를 테스트 파일의 전역변수로 사용할 필요가 있었습니다.
그럴 경우, 아래와 같이 pytest_configure()
hook 함수에 pytest.env
를 정의해두면, 테스트 파일에서 env를 바탕으로 api를 전역변수로 두고 사용할 수 있습니다.
conftest.py
def pytest_addoption(parser):
parser.addoption("--env", action="store", default='real', help="dev/real")
@pytest.fixture(scope="session")
def env(request):
return request.config.getoption("--env")
@pytest.hookimpl(tryfirst=True)
def pytest_configure(config):
pytest.env = env # pytest.env 정의
test_sample.py
env = pytest.env # pytest.env 사용
api = API(env=env)
def test_example1():
api.~~
def test_example2():
api.~~
item.funargs[‘fixture명’]
으로 hook 함수에서 fixture를 가져올 수 있습니다.
logging.ini 에 'pytest'라는 로거를 정의한 상태라고 가정하고, 테스트용 로거를 활용하는 예제입니다.
@pytest.fixture(scope="session", autouse=True)
def test_logger():
return logging.getLogger('pytest')
@pytest.hookimpl(tryfirst=True, hookwrapper=True)
def pytest_runtest_makereport(item):
test_logger = item.funcargs["test_logger"]
pytest_runtest_makereport 함수에서 테스트 함수명을 불러오고 사용하고 싶은 경우, report.nodeid
변수를 사용하면 됩니다.
아래 예시는 실패한 스크린샷 파일명에 테스트 함수명을 사용하기 위해, 테스트 함수명을 불러온 다음 불필요한 문자열을 변환하는 과정입니다.
@pytest.hookimpl(tryfirst=True, hookwrapper=True)
def pytest_runtest_makereport(item):
outcome = yield
report = outcome.get_result()
if report.when == "call":
testcase_name = re.sub(
pattern=r'::|\[',
repl='_',
string=re.sub(
pattern=r'/',
repl='__',
string=re.sub(
pattern=r'https?://|\]',
repl='',
string=report.nodeid
)
)
)