web-dev-qa-db-ja.com

グローバル変数のモック

私はモジュールのいくつかの単体テストを実装しようとしています。 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にパッチを適用しないことを好みます。これは、後で別のパラメーターで再度使用する可能性があるため、別の応答が必要になるためです。

ここで何が間違っていますか?

16
Funkatic

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

import alphabet

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

これを試して:

_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()だけでなく、個々のテストが実際に実行されている間にモックを適用する必要があります。 setUp()でモックをcreateし、後で_with ..._ Context Managerで適用できます。

26
Will

変数には、次のようにパッチを適用できます。

from mock import patch
@patch('module.variable', new_value)    

例えば:

import alphabet
from mock import patch
@patch('alphabet.letters', ['a', 'b', 'c'])
class TestAlphabet():

    def test_length_letters(self):
        assert 3 == alphabet.length_letters()

    def test_contains_letter(self):
       assert alphabet.contains_letter('a')
20
Valera Maniuk

関数またはクラスの外部で使用された変数をモックアウトしようとしていた問題に遭遇しましたが、これは値をモックする前にクラスをモックしようとするとすぐに使用されるため問題です。

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

私のテストでは、クラスがインポートされる前にこのコードがありました

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
Ruth Grace Wong