programing

메서드가 여러 개 중 하나의 인수로 호출되었다고 주장합니다.

newsource 2023. 7. 9. 11:12

메서드가 여러 개 중 하나의 인수로 호출되었다고 주장합니다.

하는 전화를 조롱하고 있습니다.requests.post사용Mock라이브러리:

requests.post = Mock()

호출에는 URL, 페이로드, 일부 인증 정보 등 여러 인수가 포함됩니다.라고 단언하고 싶습니다.requests.post특정 URL로 호출되지만 다른 인수는 신경 쓰지 않습니다.시도할 때:

requests.post.assert_called_with(requests_arguments)

해당 인수만 사용하여 호출될 것으로 예상되므로 테스트가 실패합니다.

함수 호출에서 다른 인수를 전달하지 않고 단일 인수가 사용되는지 확인할 수 있는 방법이 있습니까?

아니면 특정 URL을 주장한 다음 다른 인수에 대한 데이터 유형을 추상화하는 방법(예: 데이터는 사전이어야 하고 인증은 HTTPBasicAuth의 인스턴스여야 함)이 있습니까?

사용할 수도 있습니다.ANY사용자가 모르거나 확인하지 않는 인수를 항상 일치시키는 도우미입니다.

ANY 도우미에 대한 더 많은 정보: https://docs.python.org/3/library/unittest.mock.html#any

예를 들어 '세션' 인수를 다음과 같은 모든 것에 일치시킬 수 있습니다.

from unittest.mock import ANY
requests_arguments = {'slug': 'foo', 'session': ANY}
requests.post.assert_called_with(requests_arguments)

제가 아는 한,Mock당신이 원하는 것을 이룰 수 있는 방법을 제공하지 않습니다.assert_called_with및 멤버에 액세스하여 수동으로 어설션을 수행할 수 있습니다.

하지만 이는 여러분이 원하는 거의 모든 것을 달성하는 단순한(그리고 더러운) 방법입니다.당신은 클래스를 구현해야 합니다.__eq__메서드는 항상 반환됩니다.True:

def Any(cls):
    class Any(cls):
        def __eq__(self, other):
            return True
    return Any()

사용 방법:

In [14]: caller = mock.Mock(return_value=None)


In [15]: caller(1,2,3, arg=True)

In [16]: caller.assert_called_with(Any(int), Any(int), Any(int), arg=True)

In [17]: caller.assert_called_with(Any(int), Any(int), Any(int), arg=False)
---------------------------------------------------------------------------
AssertionError                            Traceback (most recent call last)
<ipython-input-17-c604faa06bd0> in <module>()
----> 1 caller.assert_called_with(Any(int), Any(int), Any(int), arg=False)

/usr/lib/python3.3/unittest/mock.py in assert_called_with(_mock_self, *args, **kwargs)
    724         if self.call_args != (args, kwargs):
    725             msg = self._format_mock_failure_message(args, kwargs)
--> 726             raise AssertionError(msg)
    727 
    728 

AssertionError: Expected call: mock(0, 0, 0, arg=False)
Actual call: mock(1, 2, 3, arg=True)

보다시피, 그것은 오직 그것을 확인합니다.arg다음의 하위 클래스를 만들어야 합니다.int그렇지 않으면 비교가 작동하지1 않습니다.그러나 여전히 모든 인수를 제공해야 합니다.인수가 많은 경우 튜플 언패킹을 사용하여 코드를 단축할 수 있습니다.

In [18]: caller(1,2,3, arg=True)

In [19]: caller.assert_called_with(*[Any(int)]*3, arg=True)

이를 제외하고는 모든 매개 변수를 에 전달하지 않을 방법을 생각할 수 없습니다.assert_called_with당신이 의도한 대로 일하세요.


위 솔루션을 확장하여 다른 인수 유형을 확인할 수 있습니다.예:

In [21]: def Any(cls):
    ...:     class Any(cls):
    ...:         def __eq__(self, other):
    ...:             return isinstance(other, cls)
    ...:     return Any()

In [22]: caller(1, 2.0, "string", {1:1}, [1,2,3])

In [23]: caller.assert_called_with(Any(int), Any(float), Any(str), Any(dict), Any(list))

In [24]: caller(1, 2.0, "string", {1:1}, [1,2,3])

In [25]: caller.assert_called_with(Any(int), Any(float), Any(str), Any(dict), Any(tuple))
---------------------------------------------------------------------------
AssertionError                            Traceback (most recent call last)
<ipython-input-25-f607a20dd665> in <module>()
----> 1 caller.assert_called_with(Any(int), Any(float), Any(str), Any(dict), Any(tuple))

/usr/lib/python3.3/unittest/mock.py in assert_called_with(_mock_self, *args, **kwargs)
    724         if self.call_args != (args, kwargs):
    725             msg = self._format_mock_failure_message(args, kwargs)
--> 726             raise AssertionError(msg)
    727 
    728 

AssertionError: Expected call: mock(0, 0.0, '', {}, ())
Actual call: mock(1, 2.0, 'string', {1: 1}, [1, 2, 3])

그러나 이것은 예를 들어, 둘 다가 될 수 있는 인수를 허용하지 않습니다.int또는str다중 인수 허용:Any다중 호환성을 사용하는 것은 도움이 되지 않습니다.이 문제는 다음을 사용하여 해결할 수 있습니다.

def Any(*cls):
    class Any(metaclass=abc.ABCMeta):
        def __eq__(self, other):
            return isinstance(other, cls)
    for c in cls:
        Any.register(c)
    return Any()

예:

In [41]: caller(1, "ciao")

In [42]: caller.assert_called_with(Any(int, str), Any(int, str))

In [43]: caller("Hello, World!", 2)

In [44]: caller.assert_called_with(Any(int, str), Any(int, str))

1 이름을 사용했습니다.Any함수가 코드에서 "클래스로 사용"되기 때문에 함수에 대한.또한.any기본 제공...

@mock.patch.object(module, 'ClassName')
def test_something(self, mocked):
    do_some_thing()
    args, kwargs = mocked.call_args
    self.assertEqual(expected_url, kwargs.get('url'))

참조: 튜플로서의 호출

TLDR:

args, kwargs = requests.post.call_args_list[-1]
self.assertTrue('slug' in kwargs, '`slug` not passed to requests.post')

간단히 말해서, 우리는 모든 위치 인수가 있는 튜플과 함수에 전달된 모든 명명된 인수가 있는 사전에 액세스할 수 있으므로 이제 원하는 모든 것을 확인할 수 있습니다.



는 이 왜냐하면 다음과 같은 이유 때문입니다. 이유는 다음과 같습니다.
전달되는 매개 변수가 너무 많고 그 중 하나만 확인해야 하는 경우 다음과 같은 작업을 수행합니다.{'slug': 'foo', 'field1': ANY, 'field2': ANY, 'field3': ANY, ' . . . }서투를 수 있습니다.


또한 몇 가지 필드의 데이터 유형을 확인하려면 다음을 수행합니다.

args, kwargs = requests.post.call_args_list[0]
self.assertTrue(isinstance(kwargs['data'], dict))

또한 키워드 인수 대신 인수를 전달하는 경우 다음을 통해 액세스할 수 있습니다.args다음과 같이:

self.assertEqual(
    len(args), 1,
    'post called with different number of arguments than expected'
)

Mock.call_args를 사용하여 메서드가 호출된 인수를 수집할 수 있습니다.조롱된 메서드가 호출된 경우 순서가 지정된 인수와 키워드 인수의 튜플 형식으로 메서드가 호출된 인수를 반환합니다.

class A(object):
    def a_method(self, a, b,c=None):
        print("Method A Called")

def main_method():
    # Main method instantiates a class A and call its method
    a = A()
    a.a_method("vikalp", "veer",c= "Test")

# Test main method :  We patch instantiation of A.
with patch(__name__ + '.A') as m:
    ret = m.return_value
    ret.a_method = Mock()
    res = main_method()
    args, kwargs = ret.a_method.call_args
    print(args)
    print(kwargs)

위의 코드는 다음과 같이 순서가 지정된 인수와 키워드 인수를 출력합니다.

('vikalp', 'veer')
{'c': 'Test'}

다음과 같이 주장할 수 있습니다.

assert args[0] == "vikalp"
assert kwargs['c'] == "Test"

다음 하나의 라이너는 다음과 같이 주장합니다.requests_arguments요청 호출에 대한 위치 인수 목록에 한 번 이상 나타납니다.포스트.

assert any(map(lambda args: requests_arguments in args[0], requests.post.call_args_list))

전체 작업 예제:

import unittest.mock

post = unittest.mock.Mock()
post('foo')
post('bar')
assert any(map(lambda args: 'foo' in args[0], requests.post.call_args_list))

assert_any_call(args) https://docs.python.org/3/library/unittest.mock.html#unittest.mock.Mock.assert_any_call 을 사용할 수 있습니다.

requests.post .sys_any_call(syslog_call)

언급URL : https://stackoverflow.com/questions/21611559/assert-that-a-method-was-called-with-one-argument-out-of-several