views:

56

answers:

3

Hi,

I want to write a test case which will test a list of functions. Here is an example of what I want to do:

from mock import Mock
def method1 ():
    pass

def method2 ():
    pass

## The testcase will then contain:
for func in method_list:
    func = Mock()
    # continue to setup the mock and do some testing

What I want to achieve is as follows:
Step 1) Assign my local method variable to each item in method_list
Step 2) Monkeypatch the method. In this example I am using a mock.Mock object

What actually occurs is:
Step 1) method is successfully assigned to an item from method_list - OK
Step 2) method is then assigned to the object Mock() - NOK

What I wanted in step 2 was to get the item from method_list e.g. method1 to be assigned to the Mock() object. The end result would be that both method and method1 would point to the same Mock() object

I realise that what I am essentially doing is a = b
a = c
and then expecting c==b !

I guess this is not really possible with out somehow getting a pointer to b ?

+1  A: 

Um, how about simply modifiying method_list?

for i in range(len(method_list)): # xrange in Python 2
    method_list[i] = Mock()

What you describe is closer to C++ references than to pointers. Few languages have such semantics (a few provide a special keyword for pass-by-reference), including Python.

delnan
@delnan, I think your solution has the same problem that I encounter. By setting method_list[i] to Mock() you have set the item at index i to be Mock(), whereas the old item at index i was not modified at all. But your input is very much appreciated
ephesian
@ephesian If you really want to modify *all* references to a specific object, then it's just not possible. Is the problem that e.g. `method1` still refers to the same function? Then see katrielalex's post.
delnan
+1  A: 

If I understand you correctly, you want to change what the variable method1 points to? Is that right?

You can do this by modifying its entry in the dictionary of local variables:

for method_name in [ 'method1', 'method2' ]:
    locals()[ method_name ] = Mock( )

The reason your previous code doesn't do what you want is that func is a reference to the function method1. By assigning to is, you simply change what it points to.

Are you sure you want to do this?

Monkeypatching is nasty and can cause many problems.

katrielalex
@katrielalex: that's a neat trick with locals(), I hadn't though to approach it like that. Yeah, monkeypatching can have unwanted side effects if you are not careful, but I'm using this for a test suite and it is just really useful for isolation. Thanks for your help
ephesian
+1  A: 

Something like this?

from mock import Mock
def method1 ():
    pass

def method2 ():
    pass

method_list=list(f for f in globals() if hasattr(globals()[f],'__call__') and f.startswith('method'))
print method_list
## The testcase will then contain:
for func in method_list:
    globals()[func] = Mock(func)
    # continue to setup the mock and do some testing

I am not so sure this is sensible thing to do, though. Looks like something to do with decorators.

Tony Veijalainen
@Tony: thanks, that is a useful way to get the list of methods. Unfortunately they don't all start with the same string, but I get the idea
ephesian