단위 테스트를 위해 패치를 사용하여 두 함수를 조롱


78

단위 테스트를 원하는 함수가 있는데 두 개의 다른 함수를 호출합니다. 패치를 사용하여 두 기능을 동시에 적절하게 모의 할 수있는 방법이 확실하지 않습니다. 나는 아래에 내가 의미하는 바의 예를 제공했습니다. nosetest를 실행하면 테스트는 통과하지만이를 수행하는 더 깨끗한 방법이 있어야한다고 생각하며 f.close ()에 관한 부분을 실제로 이해하지 못합니다.

디렉토리 구조는 다음과 같습니다.

program/
  program/
    data.py
  tests/
    data_test.py

data.py :

import cPickle

def write_out(file_path, data):
    f = open(file_path, 'wb')
    cPickle.dump(data, f)
    f.close()

data_test.py :

from mock import MagicMock, patch

def test_write_out():
    path = '~/collection'
    mock_open = MagicMock()
    mock_pickle = MagicMock()
    f_mock = MagicMock()
    with patch('__builtin__.open', mock_open):
        f = mock_open.return_value
        f.method.return_value = path
        with patch('cPickle.dump', mock_pickle):
            write_out(path, 'data')
            mock_open.assert_called_once_with('~/collection', 'wb')
            f.close.assert_any_call()
            mock_pickle.assert_called_once_with('data', f)

결과 :

$ nosetests
.
----------------------------------------------------------------------
Ran 1 test in 0.008s
OK

1
원래 질문이 명확하지 않은 것 같아 정리했습니다. 이것이 제가 찾고있는 것을 더 정확하게 보여주기를 바랍니다!
cnodell 2013

답변:


113

패치 데코레이터를 사용하고 다음과 같이 중첩하여 테스트를 단순화 할 수 있습니다 ( MagicMock기본적으로 객체입니다).

@patch('cPickle.dump')
@patch('__builtin__.open')
def test_write_out(mock_open, mock_pickle):
    path = '~/collection'
    f = mock_open.return_value
    f.method.return_value = path

    write_out(path, 'data')

    mock_open.assert_called_once_with('~/collection', 'wb')
    mock_pickle.assert_called_once_with('data', f)
    f.close.assert_any_call()

MagicMock인스턴스를 호출 하면 새 MagicMock인스턴스가 반환되므로 반환 된 값이 다른 모의 객체와 마찬가지로 호출되었는지 확인할 수 있습니다. 이 경우 f에는 MagicMock이름이 지정됩니다 'open()'(인쇄 시도 f).


9
제안에서 각 모의에 대해 하나씩 두 개의 매개 변수를 소개합니다. 파이썬은 어떤 것이 무엇인지 어떻게 압니까? 문서에서 이것에 대한 답을 찾지 못했습니다.
단계

54
데코레이터는 상향식으로 적용되며 매개 변수의 순서가 이에 일치해야합니다. 여기를 참조하십시오 : voidspace.org.uk/python/mock/...
마티 존

1
예, 읽었지만 충분히 명확하지 않았습니다. 감사!
단계

5
여기서 매개 변수는 패치가 적용된 순서와 반대입니다.
Shubham Chaudhary 2015

우수한! 감사합니다.
R Claven

56

@Matti John 응답 외에도 patch내부 함수 를 사용할 수도 있습니다 test_write_out.

from mock import MagicMock, patch

def test_write_out():
    path = '~/collection'
    with patch('__builtin__.open') as mock_open, \
            patch('cPickle.dump') as mock_pickle:

        f = mock_open.return_value
        ...

3

여기에 간단한 예제가 어떻게 제기 테스트에 ConflictErrorcreate_collection모의를 사용 기능 :

import os
from unittest import TestCase
from mock import patch
from ..program.data import ConflictError, create_collection


class TestCreateCollection(TestCase):
    def test_path_exists(self):
        with patch.object(os.path, 'exists') as mock_method:
            mock_method.return_value = True

            self.assertRaises(ConflictError, create_collection, 'test')

mock 문서 와 Michael Foord의 멋진 mock 소개 도 참조하십시오 .


저를 도와 주셔서 감사합니다. 이것은 도움이되지만 패치를 사용하여 여러 기능을 모의하는 방법에 더 집중했습니다. 안타깝게도 제 질문은 명확하지 않았습니다. 이제 질문을 정리했습니다.
cnodell 2013
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.