Pytest 내장된 Fixtures/Function 인자

Sangyeon·2022년 3월 26일
0

Pytest

목록 보기
6/12
post-thumbnail

pytest 에서 자동화를 구현하면서 필요해서 리서치했던 주요 builtin fixture에 대해 정리한 포스팅 입니다.

pytest 실행 명령어 옵션

fixture 함수에서 사용하고 싶은 경우

request.config.getoption("--명령어옵션")  # 커맨드라인으로부터 받은 설정 값
request.config.getini("--명령어옵션")  # ini 설정파일로부터 받은 설정 값

예시

conftest.py

@pytest.fixture(scope="session")
def env(request):
	return request.config.getoption("--env")

hook 함수에서 사용하고 싶은 경우

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 : 테스트함수 -> conftest.py로 변수 가져옴

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_configure : conftest.py -> 테스트함수로 변수 가져옴

반대로, 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.~~

hook 함수에서 fixture를 사용하고 싶은 경우

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 함수에서 테스트 함수명을 불러오고 싶은 경우

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
                )
             )
         )

Reference

profile
I'm a constant learner.

0개의 댓글