Python의 다른 함수에 의해 호출된 모의 패치 1 함수

Mehvish Ashiq 2023년6월21일
  1. 모의 객체와 그 중요성
  2. 파이썬 Patch()와 그 용도
Python의 다른 함수에 의해 호출된 모의 패치 1 함수

강력한 코드를 작성할 때마다 단위 테스트는 필수적입니다. 애플리케이션 로직을 확인하고 코드 요구 사항의 다른 모든 측면을 검사하는 데 도움이 됩니다. 그러나 복잡성 및 외부 종속성과 같은 장애물로 인해 품질 테스트 사례를 작성하기가 어렵습니다.

이 시점에서 Python 모의 라이브러리인 unittest.mock은 이러한 장애물을 극복하는 데 도움이 됩니다. 오늘은 모의객체와 그 중요성, 파이썬 patch()를 이용한 다양한 예시 코드에 대해 알아보겠습니다.

모의 객체와 그 중요성

모의 개체는 예를 들어 코드가 예상대로 작동하는지 확인하기 위해 다양한 테스트를 수행하는 테스트 환경 내에서 제어된 방식으로 실제 개체의 동작을 모방합니다. 목 객체를 사용하는 과정을 모킹이라고 합니다. 테스트 품질을 향상시키는 강력한 도구입니다.

자, 요점은, 우리는 왜 조롱을 받아야 합니까? 그것을 사용하는 근본적인 이유는 무엇입니까?

다양한 원인이 Python에서 모의 사용의 중요성을 보여줍니다. 아래에서 살펴보겠습니다.

  1. 주된 이유 중 하나는 목 객체를 사용하여 코드의 동작을 개선하는 것입니다. 예를 들어 HTTP 요청(클라이언트가 서버에 있는 명명된 호스트에 대한 요청)을 테스트하고 간헐적인 실패를 유발하는지 여부를 확인하는 데 사용할 수 있습니다.
  2. 실제 HTTP 요청을 모의 개체로 대체할 수 있습니다. 이를 통해 외부 서비스 중단과 예측 가능한 방식으로 완전히 성공적인 응답을 가짜로 만들 수 있습니다.
  3. 모킹은 if 문과 except 블록을 테스트하기 어려울 때도 유용합니다. 모의 개체를 사용하여 코드의 실행 흐름을 제어하여 이러한 영역(if제외)에 도달하고 코드 적용 범위를 개선할 수 있습니다.
  4. Python 모의 개체 사용의 중요성을 높이는 또 다른 이유는 우리 코드에서 해당 개체를 사용할 수 있는 방법을 제대로 이해하고 있기 때문입니다.

파이썬 Patch()와 그 용도

Python의 모의 개체 라이브러리인 unittest.mock에는 일시적으로 대상을 모의 개체로 대체하는 patch()가 있습니다. 여기서 대상은 클래스, 메서드 또는 함수가 될 수 있습니다.

패치를 사용하려면 대상을 식별하고 patch() 함수를 호출하는 방법을 이해해야 합니다.

대상을 인식하려면 대상이 임포트 가능한지 확인한 다음 출처가 아닌 활용되는 대상을 패치합니다. 세 가지 방법으로 patch()를 호출할 수 있습니다. 클래스/함수의 데코레이터, 컨텍스트 관리자 또는 수동 시작/중지로.

클래스/함수의 데코레이터로 patch()를 사용하거나 with 문 내부의 컨텍스트 관리자에서 patch()를 사용하면 대상이 새 개체로 대체됩니다. 두 시나리오 모두 with 문 또는 함수가 존재하면 패치가 실행 취소됩니다.

시작 코드를 생성하고 addition.py 파일에 저장하고 patch()를 데코레이터, 컨텍스트 관리자 및 수동 시작/중지로 사용하기 위해 가져올 것입니다.

시작 예제 코드(addition.py 파일에 저장됨):

def read_file(filename):
    with open(filename) as file:
        lines = file.readlines()
        return [float(line.strip()) for line in lines]


def calculate_sum(filename):
    numbers = read_file(filename)
    return sum(numbers)


filename = "./test.txt"
calculate_sum(filename)

test.txt의 내용:

1
2
3

read_file()filename을 사용하여 행을 읽고 모든 행을 float 유형으로 변환합니다. 변환된 숫자의 목록을 반환하며 calculate_sum() 함수 내부의 numbers 변수에 저장합니다.

이제 calculate_sum()숫자 목록의 모든 숫자를 합산하여 다음과 같이 출력으로 반환합니다.

출력:

6.0

patch()를 데코레이터로 사용

patch()를 데코레이터로 사용하는 방법을 단계별로 살펴보겠습니다. 전체 소스 코드는 모든 단계 끝에 제공됩니다.

  • 라이브러리 및 모듈을 가져옵니다.
    import unittest
    from unittest.mock import patch
    import addition
    

    먼저 unittest 라이브러리를 가져온 다음 unittest.mock 모듈에서 patch를 가져옵니다. 그런 다음 시작 코드인 추가를 가져옵니다.

  • test_calculate_sum() 메서드를 장식합니다.
    @patch('addition.read_file')
    def test_calculate_sum(self, mock_read_file):
        # ....
    

    다음으로 @patch 데코레이터를 사용하여 test_calculate_sum() 테스트 메서드를 장식합니다. 여기서 target은 addition 모듈의 read_file() 함수입니다.

    test_calculate_sum()에는 @patch 데코레이터를 사용하기 때문에 추가 매개변수 mock_read_file이 있습니다. 이 추가 매개변수는 MagicMock의 인스턴스입니다(mock_read_file의 이름을 원하는 대로 바꿀 수 있음).

    test_calculate_sum() 내부에서 patch()addition.read_file() 함수를 mock_read_file 객체로 대체합니다.

  • 목록을 mock_read_file.return_value에 할당합니다.
    mock_read_file.return_value = [1, 2, 3]
    
  • calculate_sum()을 호출하고 테스트합니다.
    result = addition.calculate_sum("")
    self.assertEqual(result, 6.0)
    

    이제 calculate_sum()을 호출하고 assertEqual()을 사용하여 합계가 6.0인지 여부를 테스트할 수 있습니다.

    여기에서 addition.read_file() 함수 대신 mock_read_file 객체가 호출되기 때문에 calculate_sum() 함수에 filename을 전달할 수 있습니다.

  • 다음은 전체 소스 코드입니다.

    예제 코드(test_sum_patch_decorator.py 파일에 저장됨)

    import unittest
    from unittest.mock import patch
    import addition
    
    
    class TestSum(unittest.TestCase):
        @patch("addition.read_file")
        def test_calculate_sum(self, mock_read_file):
            mock_read_file.return_value = [1, 2, 3]
            result = addition.calculate_sum("")
            self.assertEqual(result, 6.0)
    

    테스트 실행:

    python -m unittest test_sum_patch_decorator -v
    

    위의 명령을 사용하여 테스트를 실행하여 다음 출력을 얻습니다.

    출력:

    test_calculate_sum (test_sum_patch_decorator.TestSum) ... ok
    
    ----------------------------------------------------------------------
    Ran 1 test in 0.001s
    
    OK
    

patch()를 컨텍스트 관리자로 사용

예제 코드(test_sum_patch_context_manager.py 파일에 저장됨):

import unittest
from unittest.mock import patch
import addition


class TestSum(unittest.TestCase):
    def test_calculate_sum(self):
        with patch("addition.read_file") as mock_read_file:
            mock_read_file.return_value = [1, 2, 3]
            result = addition.calculate_sum("")
            self.assertEqual(result, 6)

이 코드는 여기에서 논의된 몇 가지 차이점을 제외하고 patch()를 데코레이터로 사용한 마지막 코드 예제와 유사합니다.

이제 @patch('addition.read_file') 코드 라인이 없지만 test_calculate_sum()self 매개변수(기본 매개변수)만 사용합니다.

with patch('addition.read_file') as mock_read_file은 컨텍스트 관리자에서 mock_read_file 객체를 사용하는 addition.read_file() 패치를 의미합니다.

간단히 말해서 patch()addition.read_file()with 블록 내에서 mock_read_file 개체로 대체한다고 말할 수 있습니다.

이제 아래 명령을 사용하여 테스트를 실행하십시오.

python -m unittest test_sum_patch_context_manager -v

출력:

test_calculate_sum (test_sum_patch_context_manager.TestSum) ... ok

----------------------------------------------------------------------
Ran 1 test in 0.001s

OK

patch()를 사용하여 수동으로 시작/중지

예제 코드(test_sum_patch_manually.py 파일에 저장됨):

import unittest
from unittest.mock import patch
import addition


class TestSum(unittest.TestCase):
    def test_calculate_sum(self):
        patcher = patch("addition.read_file")
        mock_read_file = patcher.start()
        mock_read_file.return_value = [1, 2, 3]
        result = addition.calculate_sum("")
        self.assertEqual(result, 6.0)
        patcher.stop()

이 코드 펜스는 앞의 두 코드 예제와 동일하지만 여기서는 patch()를 수동으로 사용합니다. 어떻게? 아래에서 이해합시다.

먼저 필요한 라이브러리를 가져옵니다. test_calculate_sum() 내부에서 patch()를 호출하여 addition 모듈의 대상 read_file() 기능으로 패치를 시작합니다.

그런 다음 read_file() 함수에 대한 하나의 모의 개체를 만듭니다. 그런 다음 mock_read_file.return_value에 숫자 목록을 할당하고 calculate_sum()을 호출하고 결과를 테스트합니다assertEqual() 사용.

마지막으로 patcher 개체의 stop() 메서드를 호출하여 패치를 중지합니다. 이제 다음 명령을 실행하여 테스트하십시오.

python -m unittest test_sum_patch_manually -v

출력:

test_calculate_sum (test_sum_patch_manually.TestSum) ... ok

----------------------------------------------------------------------
Ran 1 test in 0.001s

OK
Mehvish Ashiq avatar Mehvish Ashiq avatar

Mehvish Ashiq is a former Java Programmer and a Data Science enthusiast who leverages her expertise to help others to learn and grow by creating interesting, useful, and reader-friendly content in Computer Programming, Data Science, and Technology.

LinkedIn GitHub Facebook