0

I am unit-testing my software with PyUnit and find it unfortunate that the assertions provided by mock objects (e.g. mock.assert_called_with) don't seem to provide a way to set a message in case the assertion fails. That's why I want to use a wrapper like this:

def wrap_mock_msg(mock_method, *args, msg):
try:
    mock_method(<args here!>)
except AssertionError as e:
    raise AssertionError(e.args, msg)

It takes the assertion method of a given mock object as mock_method, the message to be displayed upon failure as msg, and a series of arguments to be passed to the mock_method as args. I need it to be a variable args list, since mock.assert_called_with(arg1, arg2, .., arg_n) can also take any number of arguments, depending on the method I'm trying to mock.

Unfortunately, I can't just pass a list of arguments to the mock_method, since it will of course be taken as a single argument. Now, this leads me to the challenge of having to pass the list of arguments to the mock_method as if I had hard-typed it. For example:

args = ['an', 'example']

..should result in the following call:

mock_method('an', 'example')

Is there any way to achieve this?

R. Hahnemann
  • 175
  • 5

2 Answers2

3

You can unpack the items in the list using the * operator. You would need to pass in the arguments as a tuple this way. The code would look like this:

def wrap_mock_msg(mock_method, args, msg):
    try:
        mock_method(*args)
    except AssertionError as e:
        raise AssertionError(e.args, msg)
brandonwang
  • 1,603
  • 10
  • 17
  • There is no need in `*` operator in function definition statement: `def wrap_mock_msg(mock_method, args, msg):` – Maksim Terpilowski Aug 10 '18 at 19:24
  • You're correct. Then the arguments would need to be passed in through a list/tuple. – brandonwang Aug 10 '18 at 19:26
  • Thank you for the clarification on the * operator. I do not understand @mxmt's suggestion though. If I define the wrapper as suggested, and give the args as a tuple, the function will simply give me a TypeError since positional arguments are missing and the tuple is only passed like a list. – R. Hahnemann Aug 10 '18 at 19:30
  • What @mxmt was saying what you could pass in the arguments as a list or tuple. For example, if the arguments were 1, 2, 3, then you would call `wrap_mock_msg(mock_method, (1,2,3), some_message)` – brandonwang Aug 10 '18 at 19:32
  • Ah yes, I see my mistake. Of course, both tuples and lists can be unpacked by the *. Thank you! – R. Hahnemann Aug 10 '18 at 19:34
0

You can call:

mock_method(*args)

Unpacking works either way using the * operator. The arguments taken in the wrapper are unpacked into a list, then that list is unpacked into the function.

N Chauhan
  • 3,407
  • 2
  • 7
  • 21