2016-07-12 15 views
7

モジュールの単体テストを実装しようとしました。次のようにalphabet.pyという名前のモジュール例は次のとおりです。グローバル変数を模擬しました

import database 

def length_letters(): 
    return len(letters) 

def contains_letter(letter): 
    return True if letter in letters else False 


letters = database.get('letters') # returns a list of letters 

私は私の選択のいくつかの値を使用してデータベースからの応答を模擬したいのですが、以下のコードが動作するようには思えません。

import unittests 
import alphabet 
from unittest.mock import patch 


class TestAlphabet(unittest.TestCase): 
    @patch('alphabet.letters') 
    def setUp(self, mock_letters): 
     mock_letters.return_value = ['a', 'b', 'c'] 

    def test_length_letters(self): 
     self.assertEqual(3, alphabet.length_letters()) 

    def test_contains_letter(self): 
     self.assertTrue(alphabet.contains_letter('a')) 

「パッチ」がメソッドやクラスには適用されますが、変数には適用されない例が多数あります。私はメソッドdatabase.getにパッチを適用したくないので、後で別のパラメータで再度使用するかもしれないので、私は別の応答が必要です。

私はここで間違っていますか?

答えて

2

モックを使用する必要はありません。ただ、モジュールをインポートし、setUp()内グローバルの値を変更:

import alphabet 

class TestAlphabet(unittest.TestCase): 
    def setUp(self): 
     alphabet.letters = ['a', 'b', 'c'] 
+3

この方法の残念なことに、このモジュールレベル変数を使用する他のテストでは、古い値を保存して戻さない限り、失敗します。あなたのために嘲笑がこの世話をします。 –

+1

'alphabet.letters'の値を' tearDown'関数の元の値に戻すことができます。 – tomas

+0

また、 'setUp'はテストクラス全体にスコープされているので、この1つの値は' letters'にしか使用できません。以下の答えは、さまざまなテストケースに対して複数のモックを作成できるようにします。最後に自分自身をクリーンアップするので、誤ったテスト汚染のリスクはありません。 – raindrift

10

これを試してみてください:個々のテストは実際にだけではなくsetUp()に、実行中

import unittests 
import alphabet 
from unittest.mock import patch 


class TestAlphabet(unittest.TestCase): 
    def setUp(self): 
     self.mock_letters = mock.patch.object(
      alphabet, 'letters', return_value=['a', 'b', 'c'] 
     ) 

    def test_length_letters(self): 
     with self.mock_letters: 
      self.assertEqual(3, alphabet.length_letters()) 

    def test_contains_letter(self): 
     with self.mock_letters: 
      self.assertTrue(alphabet.contains_letter('a')) 

あなたがモックを適用する必要があります。 モックをsetUp()に作成し、後でwith ...コンテキストマネージャを使用して適用することができます。

+0

これは私が求めていたものですが、ジョンの答えは与えられた例の方が良いようです。あなたのものが他の場合にも役立つと思います。ありがとうございました。 – Funkatic

+0

問題ありません、喜んで助けてください! – Will

0

私は、関数またはクラスの外で使用された変数を模倣しようとしていた問題に遭遇しました。これは、値をモックする前にクラスをモックしようとすると問題になります。

私は環境変数を使用して終了しました。環境変数が存在する場合はその値を使用し、そうでなければアプリケーションのデフォルト値を使用します。このようにして、テストで環境変数の値を設定することができました。クラスは私のクラスでは

os.environ["PROFILER_LOG_PATH"] = "./" 

をインポートされた前に私のテストで

、私はこのコードを持っていた:デフォルトでは

log_path = os.environ.get("PROFILER_LOG_PATH",config.LOG_PATH) 

config.LOG_PATH/var/log/<my app name>ですが、今のテストが実行されている場合、ログ・パスは現行ディレクトリーに設定されます。この方法では、テストを実行するためのルートアクセスは必要ありません。

+1

理想的には、追加の設定を行わずに、すべての環境でテストを同一にする必要があります。それ以外の場合は、ローカルマシンを経由するかもしれませんが、別の場所で失敗します。 – Funkatic

関連する問題