3

私はノーズテスト ジェネレーター機能を使用して、異なるコンテキストで同じテストを実行しています。テストごとに次のボイラープレートが必要になるため:

class TestSample(TestBase):

    def test_sample(self):
        for context in contexts:
            yield self.check_sample, context

    def check_sample(self, context):
        """The real test logic is implemented here"""
        pass

次のデコレータを作成することにしました。

def with_contexts(contexts=None):        
    if contexts is None:
        contexts = ['twitter', 'linkedin', 'facebook']

    def decorator(f):
        @wraps(f)
        def wrapper(self, *args, **kwargs):
            for context in contexts:
                yield f, self, context # The line which causes the error
        return wrapper
    return decorator

デコレータは次のように使用されます。

class TestSample(TestBase):  

    @with_contexts()
    def test_sample(self, context):
        """The real test logic is implemented here"""
        var1 = self.some_valid_attribute

テストが実行されると、アクセスされている属性が使用できないことを示すエラーがスローされます。ただし、メソッドを呼び出す行を次のように変更すると、正常に動作します。

yield getattr(self, f.__name__), service

上記のスニペットはバインドされたメソッドを作成し、最初の 1 つの自己が関数に手動で渡されることを理解しています。ただし、私の理解では、最初のスニペットも問題なく動作するはずです。誰かが問題を明確にしていただければ幸いです。

質問のタイトルは、一般的にデコレーターでのインスタンス メソッドの呼び出しに関連していますが、私のコンテキストに固有の説明を保持しています。

4

2 に答える 2

3

メソッドが次のようになるようfunctools.partialに、ラップされた関数を に結び付けるために使用できます。self

from functools import partial

def decorator(f):
    @wraps(f)
    def wrapper(self, *args, **kwargs):        
        for context in contexts:
            yield partial(f, self), context
    return wrapper

代わりにパーシャルを生成しています。これは、 として呼び出されるとyieldedvalue(context)、 を呼び出しますf(self, context)

于 2012-12-10T09:35:08.127 に答える
0

私が知る限り、いくつかのことは一致しません。まず、デコレータは次のようになります

def with_contexts(contexts=None):        
    if contexts is None:
        contexts = ['twitter', 'linkedin', 'facebook']

    def decorator(f):
        @wraps(f)
        def wrapper(self, *args, **kwargs):
            for context in contexts:
                yield f, self, context # The line which causes the error
        return wrapper
    return decorator

しかし、あなたはそれを次のように使用します

@with_contexts
def test_sample(self, context):
    """The real test logic is implemented here"""
    var1 = self.some_valid_attribute

これは間違っています: これは を呼び出しますがwith_context(test_sample)、 が必要with_context()(test_sample)です。そうする

@with_contexts()
def test_sample(self, context):
    """The real test logic is implemented here"""
    var1 = self.some_valid_attribute

contexts引数を指定しなくても。

第 2 に、間違った関数を装飾します。使用法は、関数が各コンテキストtestの関数を生成することを示しています。checkラップする関数はチェック関数の仕事をしますが、テスト関数にちなんで名前を付ける必要があります。

selfメソッドへの適用partialは、Martijn が書いているように行うことができますが、Python が内部で行う方法と同じように行うこともできます。

method.__get__(self, None)

または多分より良い

method.__get__(self, type(self))

同じことを達成できます。(おそらく、元のバージョンも同様に機能し、呼び出される関数と使用する引数が生成されます。これが機能する方法であることが私には明らかではありませんでした。)

于 2012-12-10T10:02:52.120 に答える