7

次の要件を持つクラスをモックしたいと思います。

  • クラスには、その__init__()メソッドで定義されたパブリック読み取り/書き込みプロパティがあります
  • クラスには、オブジェクトの作成時に自動インクリメントされるパブリック属性があります
  • を使用したいautospec=Trueので、クラスのAPIは厳密に呼び出しをチェックします

簡略化されたクラスのサンプル:

class MyClass():
    id = 0

    def __init__(self, x=0.0, y=1.0):
        self.x = x
        self.y = y
        self.id = MyClass._id
        MyClass.id +=1

    def calc_x_times_y(self):
        return self.x*self.y

    def calc_x_div_y(self, raise_if_y_not_zero=True):
        try:
            return self.x/self.y
        except ZeroDivisionError:
            if raise_if_y_not_zero:
                raise ZeroDivisionError
            else:
                return float('nan')

プロパティに関する限り、モックオブジェクトを元のオブジェクトとして動作させる必要があります。

  • 新しく作成された各モックオブジェクトに割り当てられたIDを自動インクリメントする必要があります
  • プロパティへのアクセスを許可する必要がありますがx,y、モックメソッド呼び出しはモックによってインターセプトされ、呼び出しシグネチャが検証される必要があります

これについて続けるための最良の方法は何ですか?

編集

Mockクラスのサブクラス化、use attach_mock()、およびを含むいくつかのアプローチをすでに試しましたmock_add_spec()が、常に行き詰まりに遭遇しました。

標準のモックライブラリを使用しています。

4

2 に答える 2

3

答えが来ていないので、私は私のために働いたものを投稿します(必ずしも最良のアプローチではありませんが、ここに行きます):

オブジェクトを作成し、ここで説明する構文を使用してそのプロパティをMock()設定し、オブジェクトを返すモックファクトリを作成しました。id

 class MyClassMockFactory():
     _id = 0

     def get_mock_object(self, *args,**kwargs):
        mock = Mock(MyClass, autospec = True)
        self._attach_mock_property(mock , 'x', kwargs['x'])
        self._attach_mock_property(mock , 'y', kwargs['y'])
        self._attach_mock_property(mock , 'id', MyClassMockFactory._id)
        MyClassMockFactory._id += 1
        return mock

     def _attach_mock_property(self, mock_object, name, value):
         p = PropertyMock(return_value=value)
         setattr(type(mock_object), name, p)

MyClass()これで、テスト用にコンストラクターにパッチを適用できます。

class TestMyClass(TestCase):
     mock_factory = MyClassMockFactory()

     @patch('MyClass',side_effect=mock_factory.get_mock_object)
     test_my_class(self,*args):
         obj0 = MyClass()
         obj1 = MyClass(1.0,2.2)
         obj0.calc_x_times_y()
         # Assertions
         obj0.calc_x_times_y.assert_called_once_with()
         self.assertEqaul(obj0.id, 0)
         self.assertEqaul(obj1.id, 1)
于 2012-11-29T08:40:38.387 に答える
0

古い投稿を掘り下げて申し訳ありませんが、クラス全体の作成をモックするのではなく、パッチcalc_x_times_yを適用してそこにcalc_x_div_y設定することで、達成したいことを正確に実行できます。autospec=True

何かのようなもの:

@patch('MyClass.calc_x_times_y')
@patch('MyClass.calc_x_div_y')
test_foo(patched_div, patched_times):
my_class = MyClass() #using real class to define attributes
# ...rest of test
于 2015-06-18T18:40:14.563 に答える