How do I programmatically set the docstring? - python

I have a wrapper function that returns a function. Is there a way to programmatically set the docstring of the returned function? If I could write to __doc__ I'd do the following:
def wrapper(a):
def add_something(b):
return a + b
add_something.__doc__ = 'Adds ' + str(a) + ' to `b`'
return add_something
Then I could do
>>> add_three = wrapper(3)
>>> add_three.__doc__
'Adds 3 to `b`
However, since __doc__ is read-only, I can't do that. What's the correct way?
Edit: Ok, I wanted to keep this simple, but of course this is not what I'm actually trying to do. Even though in general __doc__ is writeable in my case it isn't.
I am trying to create testcases for unittest automatically. I have a wrapper function that creates a class object that is a subclass of unittest.TestCase:
import unittest
def makeTestCase(filename, my_func):
class ATest(unittest.TestCase):
def testSomething(self):
# Running test in here with data in filename and function my_func
data = loadmat(filename)
result = my_func(data)
self.assertTrue(result > 0)
return ATest
If I create this class and try to set the docstring of testSomething I get an error:
>>> def my_func(): pass
>>> MyTest = makeTestCase('some_filename', my_func)
>>> MyTest.testSomething.__doc__ = 'This should be my docstring'
AttributeError: attribute '__doc__' of 'instancemethod' objects is not writable

An instancemethod gets its docstring from its __func__. Change the docstring of __func__ instead. (The __doc__ attribute of functions are writeable.)
>>> class Foo(object):
... def bar(self):
... pass
...
>>> Foo.bar.__func__.__doc__ = "A super docstring"
>>> help(Foo.bar)
Help on method bar in module __main__:
bar(self) unbound __main__.Foo method
A super docstring
>>> foo = Foo()
>>> help(foo.bar)
Help on method bar in module __main__:
bar(self) method of __main__.Foo instance
A super docstring
From the 2.7 docs:
User-defined methods
A user-defined method object combines a class, a class instance (or None) and any callable
object (normally a user-defined function).
Special read-only attributes: im_self is the class instance object, im_func is the function
object; im_class is the class of im_self for bound methods or the class that asked for the
method for unbound methods; __doc__ is the method’s documentation (same as
im_func.__doc__); __name__ is the method name (same as im_func.__name__);
__module__ is the name of the module the method was defined in, or None if unavailable.
Changed in version 2.2: im_self used to refer to the class that defined the method.
Changed in version 2.6: For 3.0 forward-compatibility, im_func is also available as
__func__, and im_self as __self__.

I would pass the docstring into the factory function and use type to manually construct the class.
def make_testcase(filename, myfunc, docstring):
def test_something(self):
data = loadmat(filename)
result = myfunc(data)
self.assertTrue(result > 0)
clsdict = {'test_something': test_something,
'__doc__': docstring}
return type('ATest', (unittest.TestCase,), clsdict)
MyTest = makeTestCase('some_filename', my_func, 'This is a docstring')

This is an addition to the fact that the __doc__ attribute of classes of type type cannot be changed. The interesting point is that this is only true as long as the class is created using type. As soon as you use a metaclass you can actually just change __doc__.
The example uses the abc (AbstractBaseClass) module. It works using a special ABCMeta metaclass
import abc
class MyNewClass(object):
__metaclass__ = abc.ABCMeta
MyClass.__doc__ = "Changing the docstring works !"
help(MyNewClass)
will result in
"""
Help on class MyNewClass in module __main__:
class MyNewClass(__builtin__.object)
| Changing the docstring works !
"""

Just use decorators. Here's your case:
def add_doc(value):
def _doc(func):
func.__doc__ = value
return func
return _doc
import unittest
def makeTestCase(filename, my_func):
class ATest(unittest.TestCase):
#add_doc('This should be my docstring')
def testSomething(self):
# Running test in here with data in filename and function my_func
data = loadmat(filename)
result = my_func(data)
self.assertTrue(result > 0)
return ATest
def my_func(): pass
MyTest = makeTestCase('some_filename', my_func)
print MyTest.testSomething.__doc__
> 'This should be my docstring'
Here's a similar use case: Python dynamic help and autocomplete generation

__doc__ is not writable only when your object is of type 'type'.
In your case, add_three is a function and you can just set __doc__ to any string.

In the case where you're trying to automatically generate unittest.TestCase subclasses, you may have more mileage overriding their shortDescription method.
This is the method that strips the underlying docstring down to the first line, as seen in normal unittest output; overriding it was enough to give us control over what showed up in reporting tools like TeamCity, which was what we needed.

Related

How do I decorate an instance method with another class in Python 2.7?

In Python 2.7 I'd like to decorate an instance method test in class Foo with a decorator that is also a class called FooTestDecorator. From user Chirstop's question and the Python 2 docs' Descriptor HowTo guide I created this example.
There seems to be an issue however, when I print my decorated method object, it's (inspected?) name is wrong because it is noted as a question mark like Foo.?.
import types
class FooTestDecorator(object):
def __init__(self,func):
self.func=func
self.count=0
# tried self.func_name = func.func_name, but seemed to have no effect
def __get__(self,obj,objtype=None):
return types.MethodType(self,obj,objtype)
def __call__(self,*args,**kwargs):
self.count+=1
return self.func(*args,**kwargs)
class Foo:
#FooTestDecorator
def test(self,a):
print a
def bar(self,b):
print b
if you test it:
f=Foo()
print Foo.__dict__['test']
print Foo.test
print f.test
print Foo.__dict__['bar']
print Foo.bar
print f.bar
you get
<__main__.FooTestDecorator ...object...>
<unbound method Foo.?>
<bound method Foo.? of ...instance...>
<function bar at 0x...>
<unbound method Foo.bar>
<bound method Foo.bar of ...instance...>
You can see the replacement method is shown as Foo.?. This seems wrong.
How do I get my class-decorated instance method right?
note: My reason is that I want to use variables from the FooDecorator instance's self which I would set at init. I didn't put this in the example to keep it simpler.
Your decorator instance has no __name__ attribute, so Python has to do with a question mark instead.
Use functools.update_wrapper() to copy over the function name, plus a few other interesting special attributes (such as the docstring, the function module name and any custom attributes the function may have):
import types
from functools import update_wrapper
class FooTestDecorator(object):
def __init__(self,func):
self.func=func
self.count=0
update_wrapper(self, func)
def __get__(self,obj,objtype=None):
return types.MethodType(self,obj,objtype)
def __call__(self,*args,**kwargs):
self.count+=1
return self.func(*args,**kwargs)
Demo:
>>> f=Foo()
>>> print Foo.__dict__['test']
<__main__.FooTestDecorator object at 0x11077e210>
>>> print Foo.test
<unbound method Foo.test>
>>> print f.test
<bound method Foo.test of <__main__.Foo instance at 0x11077a830>>

Why is this working in Python nosetests when logically it should not

class TestUM:
#classmethod
def setup_class(will):
""" Setup Class"""
will.var = "TEST"
def setup(this):
""" Setup """
print this.var
def test_number(work):
""" Method """
print work.var
def teardown(orr):
""" Teardown """
print orr.var
#classmethod
def teardown_class(nott):
""" Teardown Class """
print nott.var
Run it as
nosetests -v -s test.py
I am not a Python expert but I cannot figure out why the above code works flawlessly using nose. Every print prints "TEST". What exactly is happening here.
In instance methods, the first argument is the instance itself.
In class methods, the first argument is the class itself.
In your case, rather than name that argument self or cls (the convention), you've named it this, work, orr, and nott. But they're all getting the same argument regardless of the name of the argument.
You've successfully set the attribute var to "TEST", so they all see it correctly.
Example functions without the use of classes:
def test1(attribute):
print attribute
def test2(name):
print name
def test3(cls):
print cls
def test4(self):
print self
Calling those functions:
>>> test1('hello')
hello
>>> test2('hello')
hello
>>> test3('hello')
hello
>>> test4('hello')
hello
The name of the argument doesn't matter. All that matters is what the argument is pointing at, which is always the instance or class

Testing Private Methods in Python: Unit Test or Functional Test?

After reading about testing private methods in Python, specifically referring to this accepted answer, it appears that it is best to just test the public interface. However, my class looks like this:
class MyClass:
def __init__(self):
# init code
def run(self):
self.__A()
self.__B()
self.__C()
self.__D()
def __A(self):
# code for __A
def __B(self):
# code for __B
def __C(self):
# code for __C
def __D(self):
# code for __D
Essentially, I created a class to process some input data through a pipeline of functions. In this case, it would be helpful to test each private function in turn, without exposing them as public functions. How does one go about this, if a unit test can't execute the private function?
Python does some name mangling when it puts the actually-executed code together. Thus, if you have a private method __A on MyClass, you would need to run it like so in your unit test:
from unittest import TestCase
class TestMyClass(TestCase):
def test_private(self):
expected = 'myexpectedresult'
m = MyClass()
actual = m._MyClass__A
self.assertEqual(expected, actual)
The question came up about so-called 'protected' values that are demarcated by a single underscore. These method names are not mangled, and that can be shown simply enough:
from unittest import TestCase
class A:
def __a(self):
return "myexpectedresult"
def _b(self):
return "a different result"
class TestMyClass(TestCase):
def test_private(self):
expected = "myexpectedresult"
m = A()
actual = m._A__a()
self.assertEqual(expected, actual)
def test_protected(self):
expected = "a different result"
m = A()
actual = m._b()
self.assertEqual(expected, actual)
# actual = m._A__b() # Fails
# actual = m._A_b() # Fails
First of all, you CAN access the "private" stuff, can't you? (Or am I missing something here?)
>>> class MyClass(object):
... def __init__(self):
... pass
... def __A(self):
... print('Method __A()')
...
>>> a=MyClass()
>>> a
<__main__.MyClass object at 0x101d56b50>
>>> a._MyClass__A()
Method __A()
But you could always write a test function in MyClass if you have to test the internal stuff:
class MyClass(object):
...
def _method_for_unit_testing(self):
self.__A()
assert <something>
self.__B()
assert <something>
....
Not the most elegant way to do it, to be sure, but it's only a few lines of code at the bottom of your class.
Probably you should just test the run() method. Most classes will have internal methods -- and it does not really matter in this case whether or not all the code in __A(), __B(), __C,() and __D() is actually in run() or not. If you suspect or find problems, then you might want to switch to your debugger aspect and test the private methods.

isinstance and Mocking

class HelloWorld(object):
def say_it(self):
return 'Hello I am Hello World'
def i_call_hello_world(hw_obj):
print 'here... check type: %s' %type(HelloWorld)
if isinstance(hw_obj, HelloWorld):
print hw_obj.say_it()
from mock import patch, MagicMock
import unittest
class TestInstance(unittest.TestCase):
#patch('__main__.HelloWorld', spec=HelloWorld)
def test_mock(self,MK):
print type(MK)
MK.say_it.return_value = 'I am fake'
v = i_call_hello_world(MK)
print v
if __name__ == '__main__':
c = HelloWorld()
i_call_hello_world(c)
print isinstance(c, HelloWorld)
unittest.main()
Here is the traceback
here... check type: <type 'type'>
Hello I am Hello World
True
<class 'mock.MagicMock'>
here... check type: <class 'mock.MagicMock'>
E
======================================================================
ERROR: test_mock (__main__.TestInstance)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/mock.py", line 1224, in patched
return func(*args, **keywargs)
File "t.py", line 18, in test_mock
v = i_call_hello_world(MK)
File "t.py", line 7, in i_call_hello_world
if isinstance(hw_obj, HelloWorld):
TypeError: isinstance() arg 2 must be a class, type, or tuple of classes and types
----------------------------------------------------------------------
Ran 1 test in 0.002s
Q1. Why is this error thrown? They are <class type='MagicMock>
Q2. How do I pause the mocking so that the first line will pass if the error is fixed?
From the docs:
Normally the __class__ attribute of an object will return its type. For a mock object with a spec, __class__ returns the spec class instead. This allows mock objects to pass isinstance() tests for the object they are replacing / masquerading as:
mock = Mock(spec=3)
isinstance(mock, int)
True
IMHO this is a good question and saying "don't use isinstance, use duck typing instead" is a bad answer. Duck typing is great, but not a silver bullet. Sometimes isinstance is necessary, even if it is not pythonic. For instance, if you work with some library or legacy code that isn't pythonic you must play with isinstance. It is just the real world and mock was designed to fit this kind of work.
In the code the big mistake is when you write:
#patch('__main__.HelloWorld', spec=HelloWorld)
def test_mock(self,MK):
From patch documentation we read (emphasize is mine):
Inside the body of the function or with statement, the target is patched with a new object.
That means when you patch the HelloWorld class object the reference to HelloWorld will be replaced by a MagicMock object for the context of the test_mock() function.
Then, when i_call_hello_world() is executed in if isinstance(hw_obj, HelloWorld): HelloWorld is a MagicMock() object and not a class (as the error suggests).
That behavior is because as a side effect of patching a class reference the 2nd argument of isinstance(hw_obj, HelloWorld) becomes an object (a MagicMock instance). This is neither a class or a type. A simple experiment to understand this behavior is to modify i_call_hello_world() as follows:
HelloWorld_cache = HelloWorld
def i_call_hello_world(hw_obj):
print 'here... check type: %s' %type(HelloWorld_cache)
if isinstance(hw_obj, HelloWorld_cache):
print hw_obj.say_it()
The error will disappear because the original reference to HelloWorld class is saved in HelloWorld_cache when you load the module. When the patch is applied it will change just HelloWorld and not HelloWorld_cache.
Unfortunately, the previous experiment doesn't give us any way to play with cases like yours because you cannot change the library or legacy code to introduce a trick like this. Moreover, these are that kind of tricks that we would like to never see in our code.
The good news is that you can do something ,but you cannot just patch the HelloWord reference in the module where you have isinstace(o,HelloWord) code to test. The best way depends on the real case that you must solve. In your example you can just create a Mock to use as HelloWorld object, use spec argument to dress it as HelloWorld instance and pass the isinstance test. This is exactly one of the aims for which spec is designed. Your test would be written like this:
def test_mock(self):
MK = MagicMock(spec=HelloWorld) #The hw_obj passed to i_call_hello_world
print type(MK)
MK.say_it.return_value = 'I am fake'
v = i_call_hello_world(MK)
print v
And the output of just unittest part is
<class 'mock.MagicMock'>
here... check type: <type 'type'>
I am fake
None
Michele d'Amico provides the correct answer in my view and I strongly recommend reading it. But it took me a while a grok and, as I'm sure I'll be coming back to this question in the future, I thought a minimal code example would help clarify the solution and provide a quick reference:
from mock import patch, mock
class Foo(object): pass
# Cache the Foo class so it will be available for isinstance assert.
FooCache = Foo
with patch('__main__.Foo', spec=Foo):
foo = Foo()
assert isinstance(foo, FooCache)
assert isinstance(foo, mock.mock.NonCallableMagicMock)
# This will cause error from question:
# TypeError: isinstance() arg 2 must be a class, type, or tuple of classes and types
assert isinstance(foo, Foo)
You can do it by being inherited from the MagicMock class and overriding the __subclasscheck__ method:
class BaseMagicMock(MagicMock):
def __subclasscheck__(self, subclass):
# I couldn't find another way to get the IDs
self_id = re.search("id='(.+?)'", self.__repr__()).group(1)
subclass_id = re.search("id='(.+?)'", subclass.__repr__()).group(1)
return self_id == subclass_id
# def __instancecheck__(self, instance) for `isinstance`
And then you can use this class with the #patch decorator:
class FooBarTestCase(TestCase):
...
#patch('app.services.ClassB', new_callable=BaseMagicMock)
#patch('app.services.ClassA', new_callable=BaseMagicMock)
def test_mock_for_issubclass_support(self, ClassAMock, ClassBMock):
check_for_subclasses(ClassAMock)
That's it!
Remarks:
You MUST mock all classes which are compared using issubclass.
Example:
def check_for_subclasses(class_1):
if issubclass(class_1, ClassA): # it's mocked above using BaseMagicMock
print("This is Class A")
if issubclass(class_1, ClassB): # it's mocked above using BaseMagicMock
print("This is Class B")
if issubclass(class_1, ClassC): # it's not mocked with #patch
print("This is Class C")
issubclass(class_1, ClassC) will cause an error
{TypeError}issubclass() arg 1 must be a class because ClassC contains a default __issubclass__ method. And then we should handle the test like this:
class FooBarTestCase(TestCase):
...
#patch('app.services.ClassC', new_callable=BaseMagicMock)
#patch('app.services.ClassB', new_callable=BaseMagicMock)
#patch('app.services.ClassA', new_callable=BaseMagicMock)
def test_mock_for_issubclass_support(self, ClassAMock, ClassBMock):
check_for_subclasses(ClassAMock)
Just patch the isinstance method with:
#patch('__main__.isinstance', return_value=True)
So you will get expected behavior and coverage, you can always assert that mock method was called, see test case sample below:
class HelloWorld(object):
def say_it(self):
return 'Hello I am Hello World'
def i_call_hello_world(hw_obj):
print('here... check type: %s' %type(HelloWorld))
if isinstance(hw_obj, HelloWorld):
print(hw_obj.say_it())
from unittest.mock import patch, MagicMock
import unittest
class TestInstance(unittest.TestCase):
#patch('__main__.isinstance', return_value=True)
def test_mock(self,MK):
print(type(MK))
MK.say_it.return_value = 'I am fake'
v = i_call_hello_world(MK)
print(v)
self.assertTrue(MK.say_it.called)
#patch('__main__.isinstance', return_value=False)
def test_not_call(self, MK):
print(type(MK))
MK.say_it.return_value = 'I am fake'
v = i_call_hello_world(MK)
print(v)
self.assertFalse(MK.say_it.called)
I've been wrestling with this myself lately while writing some unit tests. One potential solution is to not actually try to mock out the entire HelloWorld class, but instead mock out the methods of the class that are called by the code you are testing. For example, something like this should work:
class HelloWorld(object):
def say_it(self):
return 'Hello I am Hello World'
def i_call_hello_world(hw_obj):
if isinstance(hw_obj, HelloWorld):
return hw_obj.say_it()
from mock import patch, MagicMock
import unittest
class TestInstance(unittest.TestCase):
#patch.object(HelloWorld, 'say_it')
def test_mock(self, mocked_say_it):
mocked_say_it.return_value = 'I am fake'
v = i_call_hello_world(HelloWorld())
self.assertEquals(v, 'I am fake')
I think it's safe to use freezegun. All the necessary preparations for correctly mocking the datetime module are made there. Also, the isinstance check does not fail for me.
It works like this:
#freeze_time("2019-05-15")
def test_that_requires_frozen_time(): ...
isinstance is a built-in function, and it is not a good idea to patch built-in functions as it is explained in this answer. In order to make isinstance return the value you want, and avoid this error:
TypeError: isinstance() arg 2 must be a type or tuple of types
You can patch isinstance in the module under test. I also encourage you to use patch as a context manager in a with statement as follows:
from mock import patch
def test_your_test(self):
# your test set up
with patch('your_module.isinstance', return_value=True): # or False
# logic that uses isinstance
Using patch as a context manager allows you to mock just in the specific function/method that you want to mock it instead of mocking it in the whole test.
I guess the possible solution can be the checking of the subclass of object.
issubclass(hw_obj.__class__, HelloWorld)
Example:
from unittest.mock import patch, MagicMock
import unittest
class HelloWorld(object):
def say_it(self):
return 'Hello I am Hello World'
def i_call_hello_world(hw_obj):
print('here... check type: %s' % type(HelloWorld))
if isinstance(hw_obj, HelloWorld) or issubclass(hw_obj.__class__, HelloWorld):
print(hw_obj.say_it())
class TestInstance(unittest.TestCase):
#patch('__main__.isinstance', return_value=True)
def test_mock(self, MK):
print(type(MK))
MK.say_it.return_value = 'I am fake'
v = i_call_hello_world(MK)
print(v)
self.assertTrue(MK.say_it.called)
#patch('__main__.isinstance', return_value=False)
def test_not_call(self, MK):
print(type(MK))
MK.say_it.return_value = 'I am fake'
v = i_call_hello_world(MK)
print(v)
self.assertFalse(MK.say_it.called)
if __name__ == '__main__':
unittest.main()
I came to the same problem.
According to this answer https://stackoverflow.com/a/49718531/11277611
You can't mock the second argument of isinstance()
I don't know the solution but I know a good workaround:
It's good architecture point to hind all checks (like isintanse) inside separate functions because it's not directly related dependency, in most cases you will change the checks but preserve the behavior.
Put isinstance check into separate function and check it separately.
def logic_checks() -> bool:
...
return isinstance(mock, MyMock)
def main_func()
if logic_checks() is not True:
...
...
def test_main_func()
logic_checks = Mock(return_value=True)
main_func()
logic_checks.assert_called_once_with()
...
def test_logic_checks()
... # Here separate checks with another patches, mocks, etc.
Don't use isinstance, instead check for the existence of the say_it method. If the method exists, call it:
if hasattr(hw_obj, 'say_it'):
print hw_obj.say_it()
This is a better design anyway: relying on type information is much more brittle.

Mocking a class: Mock() or patch()?

I am using mock with Python and was wondering which of those two approaches is better (read: more pythonic).
Method one: Just create a mock object and use that. The code looks like:
def test_one (self):
mock = Mock()
mock.method.return_value = True
self.sut.something(mock) # This should called mock.method and checks the result.
self.assertTrue(mock.method.called)
Method two: Use patch to create a mock. The code looks like:
#patch("MyClass")
def test_two (self, mock):
instance = mock.return_value
instance.method.return_value = True
self.sut.something(instance) # This should called mock.method and checks the result.
self.assertTrue(instance.method.called)
Both methods do the same thing. I am unsure of the differences.
Could anyone enlighten me?
mock.patch is a very very different critter than mock.Mock. patch replaces the class with a mock object and lets you work with the mock instance. Take a look at this snippet:
>>> class MyClass(object):
... def __init__(self):
... print 'Created MyClass#{0}'.format(id(self))
...
>>> def create_instance():
... return MyClass()
...
>>> x = create_instance()
Created MyClass#4299548304
>>>
>>> #mock.patch('__main__.MyClass')
... def create_instance2(MyClass):
... MyClass.return_value = 'foo'
... return create_instance()
...
>>> i = create_instance2()
>>> i
'foo'
>>> def create_instance():
... print MyClass
... return MyClass()
...
>>> create_instance2()
<mock.Mock object at 0x100505d90>
'foo'
>>> create_instance()
<class '__main__.MyClass'>
Created MyClass#4300234128
<__main__.MyClass object at 0x100505d90>
patch replaces MyClass in a way that allows you to control the usage of the class in functions that you call. Once you patch a class, references to the class are completely replaced by the mock instance.
mock.patch is usually used when you are testing something that creates a new instance of a class inside of the test. mock.Mock instances are clearer and are preferred. If your self.sut.something method created an instance of MyClass instead of receiving an instance as a parameter, then mock.patch would be appropriate here.
I've got a YouTube video on this.
Short answer: Use mock when you're passing in the thing that you want mocked, and patch if you're not. Of the two, mock is strongly preferred because it means you're writing code with proper dependency injection.
Silly example:
# Use a mock to test this.
my_custom_tweeter(twitter_api, sentence):
sentence.replace('cks','x') # We're cool and hip.
twitter_api.send(sentence)
# Use a patch to mock out twitter_api. You have to patch the Twitter() module/class
# and have it return a mock. Much uglier, but sometimes necessary.
my_badly_written_tweeter(sentence):
twitter_api = Twitter(user="XXX", password="YYY")
sentence.replace('cks','x')
twitter_api.send(sentence)
Key points which explain difference and provide guidance upon working with unittest.mock
Use Mock if you want to replace some interface elements(passing args) of the object under test
Use patch if you want to replace internal call to some objects and imported modules of the object under test
Always provide spec from the object you are mocking
With patch you can always provide autospec
With Mock you can provide spec
Instead of Mock, you can use create_autospec, which intended to create Mock objects with specification.
In the question above the right answer would be to use Mock, or to be more precise create_autospec (because it will add spec to the mock methods of the class you are mocking), the defined spec on the mock will be helpful in case of an attempt to call method of the class which doesn't exists ( regardless signature), please see some
from unittest import TestCase
from unittest.mock import Mock, create_autospec, patch
class MyClass:
#staticmethod
def method(foo, bar):
print(foo)
def something(some_class: MyClass):
arg = 1
# Would fail becuase of wrong parameters passed to methd.
return some_class.method(arg)
def second(some_class: MyClass):
arg = 1
return some_class.unexisted_method(arg)
class TestSomethingTestCase(TestCase):
def test_something_with_autospec(self):
mock = create_autospec(MyClass)
mock.method.return_value = True
# Fails because of signature misuse.
result = something(mock)
self.assertTrue(result)
self.assertTrue(mock.method.called)
def test_something(self):
mock = Mock() # Note that Mock(spec=MyClass) will also pass, because signatures of mock don't have spec.
mock.method.return_value = True
result = something(mock)
self.assertTrue(result)
self.assertTrue(mock.method.called)
def test_second_with_patch_autospec(self):
with patch(f'{__name__}.MyClass', autospec=True) as mock:
# Fails because of signature misuse.
result = second(mock)
self.assertTrue(result)
self.assertTrue(mock.unexisted_method.called)
class TestSecondTestCase(TestCase):
def test_second_with_autospec(self):
mock = Mock(spec=MyClass)
# Fails because of signature misuse.
result = second(mock)
self.assertTrue(result)
self.assertTrue(mock.unexisted_method.called)
def test_second_with_patch_autospec(self):
with patch(f'{__name__}.MyClass', autospec=True) as mock:
# Fails because of signature misuse.
result = second(mock)
self.assertTrue(result)
self.assertTrue(mock.unexisted_method.called)
def test_second(self):
mock = Mock()
mock.unexisted_method.return_value = True
result = second(mock)
self.assertTrue(result)
self.assertTrue(mock.unexisted_method.called)
The test cases with defined spec used fail because methods called from something and second functions aren't complaint with MyClass, which means - they catch bugs, whereas default Mock will display.
As a side note there is one more option: use patch.object to mock just the class method which is called with.
The good use cases for patch would be the case when the class is used as inner part of function:
def something():
arg = 1
return MyClass.method(arg)
Then you will want to use patch as a decorator to mock the MyClass.

Categories

Resources