2017-09-07 3 views
0

単体テストで少し外に出ることは容易に認めます。 私はテストに合格していますが、私の解決策は洗練されていないと感じています。インポートされたモジュールでPython Unittestでファイルをモックする

テストされているクラス:

class Config(): 

    def __init__(self): 
     config_parser = ConfigParser() 
     try: 
      self._read_config_file(config_parser) 
     except FileNotFoundError as e: 
      pass 

     self.token = config_parser.get('Tokens', 'Token',) 

    @staticmethod 
    def _read_config_file(config): 
     if not config.read(os.path.abspath(os.path.join(BASE_DIR, ROOT_DIR, CONFIG_FILE))): 
      raise FileNotFoundError(f'File {CONFIG_FILE} not found at path {BASE_DIR}{ROOT_DIR}') 

醜いテスト:

class TestConfiguration(unittest.TestCase): 

    @mock.patch('config.os.path.abspath') 
    def test_config_init_sets_token(self, mockFilePath: mock.MagicMock): 
     with open('mock_file.ini', 'w') as file: #here's where it gets ugly 
      file.write('[Tokens]\nToken: token') 
     mockFilePath.return_value = 'mock_file.ini' 

     config = Config() 

     self.assertEqual(config.token, 'token') 
     os.remove('mock_file.ini') #quite ugly 

は編集:私は何を意味することは、私はファイルを作成する代わりに、のいずれかをからかっていました。 誰もがファイルオブジェクトをmockする方法を知っていますが、そのデータセットはASCIIテキストを読み込むように設定されていますか?クラスは深く埋まっています。 それ以外は、でデータを設定する方法はConfigParserです。確かに、テストは "うまくいく"、うまくやっていない。他のテストの行動について尋ねたものについては

が、ここでは、このクラスでは別のテストの例です:

@mock.patch('config.os.path.abspath') 
def test_warning_when_file_not_found(self, mockFilePath: mock.MagicMock): 
    mockFilePath.return_value = 'mock_no_file.ini' 

    with self.assertRaises(FileNotFoundError): 
     config.Config._read_config_file(ConfigParser()) 

はお時間をいただき、ありがとうございます。

+0

これは不合理ではないようです。別の解決策として 'Config()'インスタンスをインスタンス化する前に 'BASE_DIR'、' ROOT_DIR'、 'CONFIG_FILE'をモジュールで設定することができませんでしたか?あなたの 'Config'クラスがオプションのパラメータとして設定ファイルへのパスを受け入れるなら、どうでしょうか? – larsks

+1

私はあなたが 'ConfigParser'をテストするべきではないと思います。 '_read_config_file'は、それが何を意味するのか、設定ファイルを読み込み、それができないときに例外を送出することをテストするべきです。 –

+0

ありがとう、@larsks。私はそのユーティリティも参照していますが、今は、私の設定に関連するすべての情報を1つの場所に保存することに興味があります(つまり、 '.ini'ファイルの名前を' .ini'ファイル)。本当に私に迷惑をかけているのは、 'ConfigParser'クラスが' .read'を呼び出すときにファイル情報を設定する方法です。むしろ、アスキー文字を使ってデータを設定する嘲笑されたファイルオブジェクトにパッチを当てたいのですが、クラスが設計されている方法はそれを直感的にするものではありません。 self.assertRaisesと '(FileNotFoundError)::' ' config.Config._read_config_file(config.ConfigParser())' を - –

答えて

0

私はそれを見つけました!

私はいくつかの輸入から始めなければならなかった:from io import TextIOWrapper, BytesIO

これは、ファイルオブジェクトを作成することができます:TextIOWrapper(BytesIO(b'<StringContentHere>'))

次の部分はで、それはopen()を呼び出すことを確認するためにconfigparserモジュールに掘り関与mock.patchに命令してください、そしてここに私たちはそれを持っています、単体テスト!

@mock.patch('configparser.open') 
def test_bot_init_sets_token(self, mockFileOpen: mock.MagicMock): 

    mockFileOpen.return_value = TextIOWrapper(BytesIO(b'[Tokens]\nToken: token')) 

    config = Config() 

    self.assertEqual(config.token, 'token') 
関連する問題