연습

완료됨

이 연습에서는 pytest를 포함한 를 사용하여 함수를 테스트합니다. 그런 다음, 테스트 클래스를 업데이트하여 setup()teardown() 메서드 대신 픽스쳐를 사용합니다. parametrize를 사용하고 픽스쳐로 작업하면 테스트를 만들거나 업데이트할 때 더 유연해질 수 있습니다.

1단계 - 이 연습을 위해 테스트 파일 추가

  1. test_advanced.py라는 새 테스트 파일을 만들고 다음 코드를 추가합니다.

    def str_to_bool(string):
        if string.lower() in ['yes', 'y', '1']:
            return True
        elif string.lower() in ['no', 'n', '0']:
            return False
    
    

    str_to_bool() 함수는 문자열을 입력으로 허용하며 해당 내용에 따라 True 또는 False 값을 반환합니다.

  2. 동일한 파일에서str_to_bool() 함수에 대한 테스트를 추가합니다. 먼저 pytest.mark.parametrize()를 사용하여 모든 실제 값을 테스트합니다.

    import pytest 
    
    @pytest.mark.parametrize("string", ['Y', 'y', '1', 'YES'])
    def test_str_to_bool_true(string):
        assert str_to_bool(string) is True
    
  3. 다음으로, false 값으로 다른 테스트를 추가합니다.

    @pytest.mark.parametrize("string", ['N', 'n', '0', 'NO'])
    def test_str_to_bool_false(string):
        assert str_to_bool(string) is False
    

    이제 TrueFalse 반환 값 모두에 대해 가능한 모든 입력을 다루는 두 가지 테스트가 있습니다.

참고 항목

실제 코드와 동일한 파일 내에 테스트가 있는 것은 일반적이지 않습니다. 간단히 하기 위해 이 연습의 예제에는 동일한 파일에 실제 코드가 있습니다. 실제 Python 프로젝트에서 테스트는 테스트 중인 코드와 파일 및 디렉터리로 구분됩니다.

2단계 - 테스트 실행 및 보고서 살펴보기

테스트를 추가한 후 다음 단계는 pytest를 실행하고 출력을 검사하는 것입니다. 모든 입력 값이 별도의 테스트로 처리되는 것을 볼 수 있도록 증가된 세부 정보 표시 플래그(-v)를 사용합니다.

$ pytest -v test_avanced.py
============================= test session starts ==============================
Python 3.9.6, pytest-6.2.5, py-1.11.0, pluggy-1.0.0 
rootdir: /private
collected 8 items

test_advanced.py::test_str_to_bool_true[Y] PASSED                        [ 12%]
test_advanced.py::test_str_to_bool_true[y] PASSED                        [ 25%]
test_advanced.py::test_str_to_bool_true[1] PASSED                        [ 37%]
test_advanced.py::test_str_to_bool_true[YES] PASSED                      [ 50%]
test_advanced.py::test_str_to_bool_false[N] PASSED                       [ 62%]
test_advanced.py::test_str_to_bool_false[n] PASSED                       [ 75%]
test_advanced.py::test_str_to_bool_false[0] PASSED                       [ 87%]
test_advanced.py::test_str_to_bool_false[NO] PASSED                      [100%]

============================== 8 passed in 0.01s ===============================

두 개의 테스트 함수만 작성했지만 pytestparametrize() 함수 덕분에 총 8개의 테스트를 만들 수 있었습니다.

3단계 - 기존 테스트를 픽스쳐로 포팅

  1. test_advanced.py 파일에 새 클래스 기반 테스트를 추가합니다. 이 테스트는 일부 텍스트가 있는 임시 파일을 만드는 setup()teardown() 함수를 사용해야 합니다. 각 테스트 후에 파일이 제거됩니다. 다음과 같이 표시됩니다.

    import os
    
    
    class TestFile:
    
        def setup(self):
            with open("/tmp/done", 'w') as _f:
                _f.write("1")
    
        def teardown(self):
            try:
                os.remove("/tmp/done")
            except OSError:
                pass
    
        def test_done_file(self):
            with open("/tmp/done") as _f:
                contents = _f.read()
            assert contents == "1"
    

    이 테스트 클래스는 파일을 만들지만 /tmp/ 경로가 모든 시스템에 있다고 보장되지 않으므로 문제가 됩니다.

  2. pytest tmpdir() 픽스쳐를 사용하여 파일에 쓰고 경로를 반환하는 픽스쳐를 만듭니다.

    import pytest
    
    @pytest.fixture
    def tmpfile(tmpdir):
        def write():
            file = tmpdir.join("done")
            file.write("1")
            return file.strpath
        return write
    

    tmpfile() 픽스쳐는 테스트가 완료된 후 정리되는 유효한 임시 파일을 보장하는 pytest의 tmpdir() 픽스쳐를 사용합니다.

  3. 도우미 메서드 대신 픽스쳐를 사용할 수 있도록 TestFile 클래스를 업데이트합니다.TestFile

    class TestFile:
    
        def test_f(self, tmpfile):
            path = tmpfile()
            with open(path) as _f:
                contents = _f.read()
            assert contents == "1"
    

    이제 이 테스트 클래스는 임시 파일이 만들어지고 어설션이 작동하기 위한 적절한 콘텐츠가 있도록 할 수 있습니다.

작업 확인

이제 다음 코드를 사용하여 test_advanced.py라는 Python 파일이 있어야 합니다.

  • 문자열을 수락하고 문자열의 내용에 따라 부울 값을 반환하는 str_to_bool() 함수입니다.
  • str_to_bool() 함수에 대한 두 개의 parametrize된 테스트입니다. 하나는 True 값을 테스트하고 다른 하나는 False 값을 테스트합니다.
  • 일부 콘텐츠가 포함된 임시 pytest 파일을 만들기 위해 tmpdir() 픽스쳐를 사용하는 사용자 지정 픽스쳐입니다.
  • 사용자 지정 tmpfile() 픽스쳐를 사용하여 파일을 만드는 테스트 클래스입니다.

모든 테스트는 터미널에서 실행할 때 오류 없이 통과해야 합니다.