2016-11-03 22 views
1

ファイル上で動作するコードをテストしようとしていますが、実際のファイルを使用して置き換える方法については頭を奪うことができません。mockそしてio.StringIO 私のコードはかなり次のようである:Pythonテスト:mockとio.StringIOで偽ファイルを使用する

class CheckConfig(object): 
    def __init__(self, config): 
     self.config = self._check_input_data(config) 

    def _check_input_data(self, data): 
     if isinstance(data, list): 
      return self._parse(data) 
     elif os.path.isfile(data): 
      with open(data) as f: 
       return self._parse(f.readlines()) 

    def _parse(self, data): 
     return data 

私はそれはそれはそれを開き、リストに内容を抽出し、ファイルの場合は、リストまたはファイルのいずれかを取ることができ、クラスを持っているし、次にん結果リストに必要なこと。私は、ファイルシステムへの呼び出しを交換したい

def test_CheckConfig_with_file(): 
    config = 'config.txt' 
    expected = parsed_file_data 
    actual = CheckConfig(config).config 
    assert expected == actual 

次のように

は、私が働いてテストを持っています。私はio.StringIOとファイルを置き換えようとしましたが、os.path.isfile()からTypeErrorが得られます。文字列、バイト、またはintのいずれかが必要です。また、私はそうのようなisfile方法からかってみました:

@mock.patch('mymodule.os.path') 
def test_CheckConfig_with_file(mock_path): 
    mock_path.isfile.return_value = True 
    config = io.StringIO('data') 
    expected = parsed_file_data 
    actual = CheckConfig(config).config 
    assert expected == actual 

をしかしisfileが何かを返すように機会を得る前_io.StringIOタイプが例外を引き起こしているように私はまだ同じTypeErrorを取得します。

os.path.isfileを偽のファイルに渡すと、どうすればTrueを返すことができますか?それとも私のコードを変更するべきですか?

+0

あなたはまた、エラーログを貼り付けることはできますか? –

答えて

2

だけ(あなたはすべての後に、開いているファイルを渡すことが予想されていない)open()コールをos.path.isfileの両方をモック、および偽のファイル名を渡します。

モックライブラリは、後者のためのユーティリティを含む:mock_open()

@mock.patch('os.path.isfile') 
def test_CheckConfig_with_file(mock_isfile): 
    mock_isfile.return_value = True 
    config_data = mock.mock_open(read_data='data') 
    with mock.patch('mymodule.open', config_data) as mock_open: 
     expected = parsed_file_data 
     actual = CheckConfig('mocked/filename').config 
     assert expected == actual 

これは(dataはなく文字列であるため)Trueを返すelif os.path.isfile(data):続いて、if isinstance(data, list):テストが偽させる、及びopen(data)mock_open()の結果からあなたの模擬データを使用するように呼び出してください。

mock_open変数を使用すると、正しいデータ(mock_open. assert_called_once_with('mocked/filename')など)を使用してopen()が呼び出されたことをアサートできます。

デモ:

>>> import os.path 
>>> from unittest import mock 
>>> class CheckConfig(object): 
...  def __init__(self, config): 
...   self.config = self._check_input_data(config) 
...  def _check_input_data(self, data): 
...   if isinstance(data, list): 
...    return self._parse(data) 
...   elif os.path.isfile(data): 
...    with open(data) as f: 
...     return self._parse(f.readlines()) 
...  def _parse(self, data): 
...   return data 
... 
>>> with mock.patch('os.path.isfile') as mock_isfile: 
...  mock_isfile.return_value = True 
...  config_data = mock.mock_open(read_data='line1\nline2\n') 
...  with mock.patch('__main__.open', config_data) as mock_open: 
...   actual = CheckConfig('mocked/filename').config 
... 
>>> actual 
['line1\n', 'line2\n'] 
>>> mock_open.mock_calls 
[call('mocked/filename'), 
call().__enter__(), 
call().readlines(), 
call().__exit__(None, None, None)] 
+0

優秀、ありがとう!これはまさに私が必要としていたものであり、私は嘲笑をより良く理解するのに役立っています。興味のないだけで、 '@ mock.patch'デコレータではなく、コンテキストマネージャを使用している理由があります。以前のテストではデコレータを使用していましたが、ここでは 'open'呼び出しの内容に' pytest.fixture'を使用していましたが、テスト機能の内部では使用できませんでした。 – bordeltabernacle

関連する問題