파이썬은 여러 반환 값을 모의


168

파이썬 mock.patch를 사용하고 있으며 각 호출의 반환 값을 변경하고 싶습니다. 주의 사항은 다음과 같습니다. 패치되는 함수에는 입력이 없으므로 입력을 기반으로 반환 값을 변경할 수 없습니다.

다음은 참조 용 코드입니다.

def get_boolean_response():
    response = io.prompt('y/n').lower()
    while response not in ('y', 'n', 'yes', 'no'):
        io.echo('Not a valid input. Try again'])
        response = io.prompt('y/n').lower()

    return response in ('y', 'yes')

내 테스트 코드 :

@mock.patch('io')
def test_get_boolean_response(self, mock_io):
    #setup
    mock_io.prompt.return_value = ['x','y']
    result = operations.get_boolean_response()

    #test
    self.assertTrue(result)
    self.assertEqual(mock_io.prompt.call_count, 2)

io.prompt"입력"의 플랫폼 독립적 (파이썬 2 및 3) 버전입니다. 그래서 궁극적으로 사용자 입력을 조롱하려고합니다. 반환 값 목록을 사용해 보았지만 작동하지 않습니다.

반환 값이 잘못된 경우 여기에서 무한 루프를 얻습니다. 결과적으로 테스트가 실제로 완료되도록 반환 값을 변경하는 방법이 필요합니다.

(이 질문에 대답하는 또 다른 방법은 단위 테스트에서 사용자 입력을 모방하는 방법을 설명하는 것입니다)


아니 DUP 이 질문에 내가 입력을 변화 할 수있는 능력이 없어 주로 때문입니다.

이 질문 에 대한 답변의 의견 중 하나는 같은 줄에 있지만 답변 / 댓글은 제공되지 않았습니다.


3
response is not 'y' or 'n' or 'yes' or 'no'없는 당신이하지 무슨 생각을하고. 여러 값에 대해 하나의 변수를 테스트하는 방법을 참조하십시오 . 문자열 값 을 비교 하거나 객체 ID가 아닌 을 비교 하는 데 사용 해서는 안됩니다 . is==
Martijn Pieters

또한 여기에주의하십시오. is문자열 리터럴을 비교 하는 데 사용하려는 것 같습니다 . 하지마 그것이 작동한다는 사실 (때로는)은 CPython의 구현 세부 사항 일뿐입니다. 또한, response is not 'y' or 'n' or 'yes' or 'no'아마도 당신이 생각하는 것을하지 않을 것입니다 ...
mgilson

답변:


300

iterable 을 할당 할 수 side_effect있으며, mock은 호출 될 때마다 시퀀스의 다음 값을 반환합니다.

>>> from unittest.mock import Mock
>>> m = Mock()
>>> m.side_effect = ['foo', 'bar', 'baz']
>>> m()
'foo'
>>> m()
'bar'
>>> m()
'baz'

Mock()문서 인용 :

side_effect 가 iterable 인 경우 mock 에 대한 각 호출은 iterable에서 다음 값을 반환합니다.

따로, 테스트 response is not 'y' or 'n' or 'yes' or 'no'는 작동 하지 않습니다 . 표현식 (response is not 'y')이 참인지 또는 참 인지 묻는 경우 'y'(항상 비어 있지 않은 문자열은 항상 참임) 등 입니다. or연산자 양쪽의 다양한 표현식 은 독립적 입니다. 여러 값에 대해 하나의 변수를 테스트하는 방법을 참조하십시오 .

또한is 문자열을 테스트 하는 데 사용 해서는 안됩니다 . CPython 인터프리터 특정 상황 에서 문자열 오브젝트를 재사용 수 있지만 이는 신뢰 할만한 동작이 아닙니다.

따라서 다음을 사용하십시오.

response not in ('y', 'n', 'yes', 'no')

대신; 이것은 등식 테스트 ( ==)를 response사용하여 동일한 내용 (값)을 가진 문자열을 참조 하는지 판별합니다 .

동일하게 적용됩니다 response == 'y' or 'yes'; 사용하는 response in ('y', 'yes')대신.


표준으로 이것을 수행하는 방법이 mock있습니까? 표준 모의와 같이 MagicMock으로 패치를 사용하는 방법이 있습니까?
Nick Humrich

@Humdinger : 이것은 stardard Mock클래스 의 기능입니다 .
Martijn Pieters

17
목록을 할당하면 파이썬 3에서만 작동하는 것으로 보입니다. 파이썬 2.7로 테스트 대신 반복자를 사용해야합니다 ( m.side_effect = iter(['foo', 'bar', 'baz'])).
user686249

1
@ user686249 : 메소드에서 지정하면 a가 아닌 lambda(함수)를 생성하기 때문에 실제로 이것을 재현 할 수 있습니다 MagicMock. 함수 객체 속성을 가질 수 없으므로 side_effect속성 반복 가능해야합니다. 그래도 방법을 지정해서는 안됩니다. 더 나은 사용 mock.patch.object(requests.Session, 'post'); 패쳐 객체의 결과가 제대로 방법에 자동 사양, 그 지원 side_effect이 제대로.
Martijn Pieters

3
@ JoeMjr2 : 반복자가 소진되면 StopIteration발생합니다. 반복자를 사용할 수 있으므로 한 번 itertools.chain(['Foo'], itertools.repeat('Bar'))생성 Foo한 다음 영원히 생성 하는 데 사용할 수 있습니다 Bar.
Martijn Pieters
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.