2016-08-11 5 views
0

mockライブラリのpatchファンクションは、どのようにインポートされるかに影響されます。関数が他のモジュールでどのようにインポートされたかにかかわらず、関数が元々定義されていた完全修飾名を使用できない深刻な理由はありますか?値のインポート方法によってパッチライブラリの動作が変わるのはなぜですか?

# WORKS! 
from mock import patch 
import inner 

def outer(x): 
    return ("outer", inner.inner(x)) 

@patch("inner.inner") 
def test(mock_inner): 
    mock_inner.return_value = "MOCK" 
    assert outer(1) == ("outer", "MOCK") 
    return "SUCCESS" 

if __name__ == "__main__": 
    print test() 

がinner.py:

def inner(x): 
    return ("inner.inner", x) 

python patch_example.pyだけ出力成功の実行 "モジュールのインポート" を使用して

は細かい

patch_example.pyに動作します。

ただし、インポートはモジュールの別名を使用して、かなり劇的な結末

はまだ直接シンボルをインポートする

# WORKS! 
from mock import patch 
import inner as inner2 

def outer(x): 
    return ("outer", inner2.inner(x)) 

@patch("inner.inner") 
def test(mock_inner): 
    mock_inner.return_value = "MOCK" 
    assert outer(1) == ("outer", "MOCK") 
    return "SUCCESS" 

if __name__ == "__main__": 
    print test() 

を働くことができます変更、しかし、完全修飾名を変更する必要があります。

直接インポート、inner.inner完全修飾名。

# FAILS! 
from mock import patch 
from inner import inner 

def outer(x): 
    return ("outer", inner(x)) 

@patch("inner.inner") 
def test(mock_inner): 
    mock_inner.return_value = "MOCK" 
    assert outer(1) == ("outer", "MOCK") 
    return "SUCCESS" 

if __name__ == "__main__": 
    print test() 

私はpatch_example.innerへの完全修飾パスを更新した場合、パッチがまだ失敗

% python patch_example.py 
Traceback (most recent call last): 
    File "patch_example.py", line 14, in <module> 
    print test() 
    File "/usr/local/lib/python2.7/site-packages/mock/mock.py", line 1305, in patched 
    return func(*args, **keywargs) 
    File "patch_example.py", line 10, in test 
    assert outer(1) == ("outer", "MOCK") 
AssertionError 

を生成します。

# FAILS! 
from mock import patch 
from inner import inner 

def outer(x): 
    return ("outer", inner(x)) 

@patch("patch_example.inner") 
def test(mock_inner): 
    mock_inner.return_value = "MOCK" 
    assert outer(1) == ("outer", "MOCK") 
    return "SUCCESS" 

if __name__ == "__main__": 
    print test() 

% python patch_example.py 

Traceback (most recent call last): 
    File "patch_example.py", line 14, in <module> 
    print test() 
    File "/usr/local/lib/python2.7/site-packages/mock/mock.py", line 1305, in patched 
    return func(*args, **keywargs) 
    File "patch_example.py", line 10, in test 
    assert outer(1) == ("outer", "MOCK") 
AssertionError 

__main__.innerを使用すると、私の完全修飾名は正しいことにパッチを当てます。

# WORKS! 
from mock import patch 
from inner import inner 

def outer(x): 
    return ("outer", inner(x)) 

@patch("__main__.inner") 
def test(mock_inner): 
    mock_inner.return_value = "MOCK" 
    assert outer(1) == ("outer", "MOCK") 
    return "SUCCESS" 

if __name__ == "__main__": 
    print test() 

版画「SUCCESS」

だから、それはどちらか元のシンボルinner.innerの完全修飾名または使用の名前を使用してfrom inner import innerとしてインポートいたときに、なぜ私は、内側の値にパッチを適用することはできませんメインのPythonモジュールではなく__name__

OS X上のPython 2.7.12でテスト

答えて

1

問題は、あなたが直接シンボルをインポートしたら、あなたは__main__モジュールで使用しているとのバインディングバインディング間一切リンクがないということですinnerモジュール。したがってpatch ing モジュールではありませんはすでにインポートされたシンボルを変更します。

patchsys.modulesディクショナリを検索して元の名前を追跡するため、エイリアスを使用してモジュールをインポートしても問題ありません(実際はモックを呼び出すとモジュールが新しくインポートされるのでpatchを呼び出したときにインポートした名前は関係ありません)

つまり、両方のバインディングは効果的に関連していないため、パッチする必要があります。パッチがinner.innerへのすべての参照がどこに終わってパッチしたかを知る方法はありません。

この場合、patchという2番目の引数は、すべてのバインディングにパッチを適用するために共有できる既存のモックオブジェクトを指定するのに便利です。

関連する問題