web-dev-qa-db-ja.com

読み取り専用プロパティをモックでモックする方法は?

mock で読み取り専用プロパティをどのようにモックしますか?

私は試した:

setattr(obj.__class__, 'property_to_be_mocked', mock.Mock())

しかし、問題はクラスのすべてのインスタンスに適用されることです...私のテストを中断します。

他にアイデアはありますか?オブジェクト全体をモックしたくはありません。この特定のプロパティのみをモックしたいと思います。

73
charlax

__get__メソッドを直接モックするよりも、プロパティをPropertyMockとしてモックする方が良いと思います。

documentation に記載されているunittest.mock.PropertyMockの検索:クラスのプロパティまたはその他の記述子として使用することを目的としたモック。 PropertyMock__get__および__set__メソッドを提供するため、フェッチ時に戻り値を指定できます。

方法は次のとおりです。

class MyClass:
    @property
    def last_transaction(self):
        # an expensive and complicated DB query here
        pass

def test(unittest.TestCase):
    with mock.patch('MyClass.last_transaction', new_callable=PropertyMock) as mock_last_transaction:
        mock_last_transaction.return_value = Transaction()
        myclass = MyClass()
        print myclass.last_transaction
        mock_last_transaction.assert_called_once_with()
131

実際、答えは documentation で(いつものように)でした。例に従っているとき、クラスではなくインスタンスにパッチを適用しただけです。

方法は次のとおりです。

class MyClass:
    @property
    def last_transaction(self):
        # an expensive and complicated DB query here
        pass

テストスイートで:

def test():
    # Make sure you patch on MyClass, not on a MyClass instance, otherwise
    # you'll get an AttributeError, because mock is using settattr and
    # last_transaction is a readonly property so there's no setter.
    with mock.patch(MyClass, 'last_transaction') as mock_last_transaction:
        mock_last_transaction.__get__ = mock.Mock(return_value=Transaction())
        myclass = MyClass()
        print myclass.last_transaction
39
charlax

おそらくスタイルの問題ですが、テストでデコレーターを好む場合は、@ jamescastlefieldの answer を次のように変更できます。

class MyClass:
    @property
    def last_transaction(self):
        # an expensive and complicated DB query here
        pass

class Test(unittest.TestCase):
    @mock.patch('MyClass.last_transaction', new_callable=PropertyMock)
    def test(mock_last_transaction):
        mock_last_transaction.return_value = Transaction()
        myclass = MyClass()
        print myclass.last_transaction
        mock_last_transaction.assert_called_once_with()
4
Eyal Levin

プロパティをオーバーライドするオブジェクトがモックオブジェクトの場合、patchを使用する必要はありません。

代わりに、 PropertyMock を作成してから、モックのtypeのプロパティをオーバーライドできます。たとえば、mock_rows.pagesプロパティをオーバーライドして(mock_page, mock_page,)を返すには:

mock_page = mock.create_autospec(reader.ReadRowsPage)
# TODO: set up mock_page.
mock_pages = mock.PropertyMock(return_value=(mock_page, mock_page,))
type(mock_rows).pages = mock_pages
2
Tim Swast

モックされたプロパティにアクセスしたかどうかをテストしたくない場合は、期待されるreturn_value

with mock.patch(MyClass, 'last_transaction', Transaction()):
    ...
0
Simon Charette