Python Unit Test - 5 mock-2

>>>>>>>>>>>>>>>>>>>>>The actual application of the content is insufficient and needs to be supplemented

3. MagicMock -- it implements some magic method s built in mock. Those that need to be manually defined in mock can be named directly and called with magiclock

Magic Mock, a subclass of mock, creates all magic methods of mock while creating the Magic Mock object. It is used to simulate the python protocol method, which is used to replace the container or object that implements the python protocol.
The magic method index of mock is recorded as__ X__ Mock built-in method.
Magic's method will not pre create relevant methods during Mock, but need to be created manually; MagicMock can pre create all magic methods, so it can be used directly.

* If you use the spec keyword argument to create a mock then attempting to set a magic method that isn't in the spec will raise an AttrributeError.
If you use the spec keyword when creating a mock object and use the magic method that the spec keyword does not have, an attribute error will be reported-- Magic of mock needs to be created manually, not pre created like magiclock.

* MagicMock is a subclass of Mock with default implementations of most of the magic methods. You can use MagicMock without having to configure the magic methods yourself.
* If you use the spec or spec_set arguments then only magic methods that exist in the spec will be created.

There are two variants of MagicMock: MagicMock and NonCallableMagicMock
reference resources: https://docs.python.org/3/library/unittest.mock.html#magicmock-and-magic-method-support , magic method supported by mock

from unittest.mock import Mock
from unittest.mock import MagicMock

class tc():
    tl1 = []
    def __init__(self):
        pass

    def tc1():
        return "tc1"

## mock
mock = Mock()

## mock spec
mock.mock_add_spec(tc)
mock.tl1
mock.tc1
mock.tl2     # spec:tc, no TL2 definition, error reported; AttributeError: Mock object has no attribute 'tl2'

#### mock's__ iter__magic method cannot be pre created and needs to be created manually
# mock.__iter__    # raise AttributeError(name), AttributeError: __iter__
mock.__iter__ = mock.return_value()
print(mock)

## magicmock
magicmock = MagicMock()
#### The pre created magic method can be called directly
magicmock.__iter__  
print(magicmock)

>>> mock.__len__
<function NonCallableMock.__setattr__.<locals>.<lambda> at 0x00FD2C00>
>>> magicmock.__len__
<MagicMock name='mock.__len__' id='91021680'>
>>> magicmock.__len__()
0
>>> 

4. PropertyMock - class unittest.mock.PropertyMock(*args, * * kwargs) -- propertymock sets a property, method, or description in an alternative class

mock instances are used as attributes or other descriptions of classes. They are provided when used__ get__ () and__ set__ () method defines its call return value.
Object calls mock to get an instance of PropertyMock without parameters, and calls the value setting of mock.

from unittest.mock import PropertyMock

pmock = PropertyMock()

class pc1:
    def __init__(self, v1):
        self.v1 = v1

    def p1(self):
        print("PropertyMock")

p = pc1(5)        # instance class, variable: 5
print(p.v1)       # call class variable, return: 5 
p.p1()            # call class method,return: PropertyMock 

pmock.return_value = 'return value'
p.v1 = pmock
print(p.v1)          # <PropertyMock id='72342288'>

type(p).v1 = pmock   # PorpertyMock as class property
                     # type(p) call __set__(self, obj, val) and __get__(self, obj, obj_type) method
print(p.v1)          # call class variable, return PropertyMock instatnce return_value

pmock.return_value = p.p1
type(p).p1 = pmock
print(p.p1)          # <PropertyMock id='79380080'> 
p.p1()               # PropertyMock

type(p).p1 = pmock   # PorpertyMock as class property
                     # type(p) call __set__(self, obj, val) and __get__(self, obj, obj_type) method
print(p.p1)          # call class method, retrun PropertyMock instatnce return_value 
p.p1()               # class initial value replace by PropertyMock 
                     # TypeError: 'str' object is not callable 

5. AsyncMock  -- New in version 3.8. 

Mock upgrade, which allows you to simulate asynchronous functions
The asynchronous version of MagicMock. When the object is recognized as an asynchronous function, the AsyncMock object is executed, and the function call result can be suspended. -- await asynchronous wait, the operation on the running thread when the program is running in order to perform some special operations.
When mock() is an asynchronous function, side will be returned after asynchronous wait_ Effect or return_value: define side_ Side returned when effect_ Effect, otherwise return_value.
If the output is an asynchronous function, the asynchronous function simulated when the simulated object is called is the asynchronous function itself.

from unittest.mock import AsyncMock, Mock, asyncio

class ac:
    def sync():
        print('sync')
    
    async def a_sync(i):
        print(i)

amock = AsyncMock(ac)
# The mock method (mock, magiclock, asynclock) of class automatically detects whether its calling method is synchronous or asynchronous
print(amock.sync)        # <MagicMock name='mock.sync' id='2810946685872'>
print(amock.a_sync)      # <AsyncMock name='mock.a_sync' id='2810946742160'>

async def await_sync(i):
    await i
    print(i)

i = amock()
print(amock.assert_awaited())   # None
##amock.called       # AssertionError: Expected mock to have been awaited.
asyncio.run(await_sync(i))    # <coroutine object AsyncMockMixin._execute_mock_call at 0x0000020DF0146440>
##print(amock.assert_not_awaited())   # AssertionError: Expected mock to not have been awaited. Awaited 1 times.
print(amock.assert_awaited())  # None

amock = AsyncMock(await_sync)
amock()      # RuntimeWarning: coroutine 'AsyncMockMixin._execute_mock_call' was never awaited
Methodexplain
assert_awaited()Assert that mock waits asynchronously at least once
assert_awaited_once()Assert that mock waits asynchronously only once
assert_awaited_with(*args, **kwargs)Assertion last waited asynchronously with a specific parameter
assert_awaited_once_with(*args, **kwargs)Assert that mock waits asynchronously once with a specific parameter
assert_any_await(*args, **kwargs)Assert any asynchronous wait
assert_has_awaits(calls, any_order=False)Assert that mock waits asynchronously with a specific call
assert_not_awaited()Assert that mock never waits asynchronously
reset_mock(*args, **kwargs)Reset mock settings
await_countAsynchronous wait times
await_argsAsynchronous wait parameter
await_args_listAsynchronous waiting parameter list

6. patchers ?
Decorator: function objects are passed as arguments.

Patch decorator is used to wrap objects within a certain functional range. It is convenient to use mock objects to temporarily replace classes in specific modules. The default patch creates an alternative class for MagicMock.
patch(), function, class or content management, used to patch new objects.

unittest.mock.patch(target, new=DEFAULT, spec=None, create=False, spec_set=None, autospec=None, new_callable=None, **kwargs)
>>Target: refers to a class method; Referenced from the called patch(), when the @ decorator function is executed, 'package module. ClassName'
>> patch(). start   /     patch().stop: mock the object through the patch () method

from unittest.mock import Mock, patch
import pmock      # self define class

patcher = patch("pmock.func",spec='patcher',first='1')   # define target: pmock.func
mock= patcher.start()   # mock path() object
print(mock.first)       # 1: call mock methoc
patcher.stop()

def tp():
    print("patcher test")
@patch("pmock.func",spec='patcher',first="patcher check first")
def test(f):
    tp()                # patcher test
    print(f.first)      # patcher check first
    print(pmock.func)   # <NonCallableMagicMock name='func' spec='str' id='3121040519120'>
    assert pmock.func == "patcher check"   # AssertionError

test() 
patchexplain
objectpatch object properties
dictpatch dictionary type
multipleName multiple patcher s in one call
start

Using patch, put the patch in place

stopundo it

7. Helper

Helpersexplain
sentinel(sentinel) a simple method that provides a specific unique object for testing, and a method that provides a specific parameter or return value to make the return information readable
DEFAULTThe pre created sentinel defines the normal return value
callImplement simple assertion on mock method call: call_args, call_args_list, mock_calls 
create_autospecCreate a new mock object with another object as a spec. the mock object uses the properties of the spec object by default?
ANYComplex assertions that achieve a specific purpose, regardless of parameters
FILTER_DIRModule level variable, which is used to control and filter the display content of dir() method of mock object?
mock_openmock open() method instead of open() method?
AutospeccingBased on the spec feature, limit the mock api of the initial object?
Sealing mocksseal(). When the properties of the accessed mock object are recursive by seal or properties, sell is used to prohibit the automatic creation of mock objects?
from unittest.mock import Mock, sentinel, call, MagicMock, ANY

class chelp:
    def __init__(self):
        pass

    def pval(self):
        print("this is helper")

ch = Mock(spec='helper', name='chelper', return_value='this test',DEFAULT='default')
# sentinel / DEFAULT
print(ch.DEFAULT)              # default
ch.DEFAULT=sentinel.DEFAULT
print(ch.DEFAULT)              # sentinel.DEFAULT

# call(*args, **kwargs)
ch(1,a='a')
print(ch.call_args_list == [call(1,a='a'),call()])   # False
ch()    # call mock                          
print(ch.call_args_list == [call(1,a='a'),call()])   # True
# call_list()
mch = MagicMock()
mch(1).method(2).other(3)(4,5)
tcall = call(1).method(2).other(3)(4,5)
print(tcall.call_list())
'''
[call(1),
 call().method(2),
 call().method().other(3),
 call().method().other()(4, 5)]
'''
print(mch.mock_calls == tcall.call_list())       # True

# ANY
print(mch.mock_calls == [call(1),call(2),ANY])   # False
mch.__init__()
mch(1)
mch(2)
mch(3)
print(mch.mock_calls == [call(1),call(2),ANY])   # True

 

 

Added by pwicks on Fri, 18 Feb 2022 19:15:19 +0200