Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
519 views
in Technique[技术] by (71.8m points)

python - Conditional mocking: Call original function if condition does match

How can I conditionally call the original method in a mock?

In this example I only want to fake a return value if bar=='x'. Otherwise I want to call the original method.

def mocked_some_method(bar):
    if bar=='x':
        return 'fake'
    return some_how_call_original_method(bar)

with mock.patch('mylib.foo.some_method', mocked_some_method):
    do_some_stuff()
    

I know that it is a bit strange. If I want to fake mylib.foo.some_method in side do_some_stuff() it should be condition-less. All (not some) calls to some_method should be mocked.

In my case it is an integration test, not a s tiny unittest and mylib.foo.some_method is a kind of dispatcher which gets used very often. And in one case I need to fake the result.

Update

I wrote this question four years ago. Today, it feels very strange to do conditional mocking. Mocks should only get used in tests. Tests (and production code) should be simple and small. Tests should be conditionless. As I wrote this question, we still used huge production methods and long test. Today, I follow these rules (simple methods, conditionless tests ...). I wrote my findings down: my programming guidelines

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

If you need just replace behavior without care of mock's calls assert function you can use new argument; otherwise you can use side_effect that take a callable.

I guess that some_method is a object method (instead of a staticmethod) so you need a reference its object to call it. Your wrapper should declare as first argument the object and your patch use autospec=True to use the correct signature for side_effect case.

Final trick is save the original method reference and use it to make the call.

orig = mylib.foo.some_method
def mocked_some_method(self, bar):
    if bar=='x':
        return 'fake'
    return orig(self, bar)

#Just replace:
with mock.patch('mylib.foo.some_method', new=mocked_some_method):
    do_some_stuff()

#Replace by mock
with mock.patch('mylib.foo.some_method', side_effect=mocked_some_method, autospec=True) as mock_some_method:
    do_some_stuff()
    assert mock_some_method.called

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...