Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use mock.ANY with assert_called_with

I'm blocked.

I'm creating tests with nosetests and Mock. It's very, very hard for me to understand how to do this properly. Here I want to make sure subprocess.check_output is called with the right parameters. I get this error message:

AssertionError: Expected call: check_output(['dscl', '/Search', 'read', '/Users/testuser', 'AuthenticationAuthority'], <ANY>)
Actual call: check_output(['dscl', '/Search', 'read', '/Users/testuser', 'AuthenticationAuthority'], stderr=-2)

Isn't mock.ANY a wildcard ? Did I misunderstand something ?

I'm not sensible, please tell me if I'm being stupid.

KerbMinder2.py:

def get_current_username():
"""Returns the user associated with the LaunchAgent running KerbMinder.py"""
    return getpass.getuser()

@staticmethod
def get_principal_from_ad():
    """Returns the principal of the current user when computer is bound"""

    import re

    user_path = '/Users/' + get_current_username()

    try:
        output = subprocess.check_output(['dscl',
                                          '/Search',
                                          'read',
                                          user_path,
                                          'AuthenticationAuthority'],
                                         stderr=subprocess.STDOUT)
        match = re.search(r'[a-zA-Z0-9+_\-\.]+@[^;]+\.[A-Z]{2,}', output, re.IGNORECASE)
        match = match.group()

    except subprocess.CalledProcessError as error:
        log_print("Can't find Principal from AD: " + str(error))

    else:
        log_print('Kerberos Principal is ' + match)
        return match

test_KerbMinder2.py:

@patch('KerbMinder2.get_current_username')
def test_ad_bound_notenabled(self, mock_get_current_username):
    #https://github.com/nens/nensbuild/blob/master/nensbuild/tests.py
    mock_get_current_username.return_value = "testuser"

    _return_value = 'AuthenticationAuthority:  ;ShadowHash;HASHLIST:' \
                    '<SMB-NT,CRAM-MD5,RECOVERABLE,SALTED-SHA512-PBKDF2>  ' \
                    ';LocalCachedUser;/Active Directory/TEST/test.com:testuser' \
                    ':9A1F2D0C-B782-488A-80BA-CAC95AB6CAE9  ;Kerberosv5;;[email protected];' \
                    'TEST.COM; AuthenticationAuthority: ;Kerberosv5;;[email protected];TEST.COM; ' \
                    ';NetLogon;testuser;TEST'
    with patch('subprocess.check_output', return_value = _return_value) as check_output:
        nose.tools.eq_(Principal.get_principal_from_ad(), "[email protected]")
    check_output.assert_called_with(['dscl',
                                      '/Search',
                                      'read',
                                      '/Users/testuser',
                                      'AuthenticationAuthority'],
                                      ANY)

RESULT

test_ad_bound_notenabled (test_KerbMinder2.TestPrincipal) ... 
FAIL


Failure
Traceback (most recent call last):
  File "/usr/local/Cellar/python/2.7.10_2/Frameworks/Python.framework/Versions/2.7/lib/python2.7/unittest/case.py", line 331, in run
    testMethod()
  File "/Users/francois/venv-KerbMinder2/lib/python2.7/site-packages/mock/mock.py", line 1305, in patched
    return func(*args, **keywargs)
  File "/Users/francois/Git/KerbMinder2/Library/Application Support/crankd/test_KerbMinder2.py", line 61, in test_ad_bound_notenabled
    ANY)
  File "/Users/francois/venv-KerbMinder2/lib/python2.7/site-packages/mock/mock.py", line 937, in assert_called_with
    six.raise_from(AssertionError(_error_message(cause)), cause)
  File "/Users/francois/venv-KerbMinder2/lib/python2.7/site-packages/six.py", line 718, in raise_from
    raise value
AssertionError: Expected call: check_output(['dscl', '/Search', 'read', '/Users/testuser', 'AuthenticationAuthority'], <ANY>)
Actual call: check_output(['dscl', '/Search', 'read', '/Users/testuser', 'AuthenticationAuthority'], stderr=-2)
-------------------- >> begin captured stdout << ---------------------
Kerberos Principal is [email protected]

--------------------- >> end captured stdout << ----------------------
like image 203
Francois T. Avatar asked Oct 19 '15 12:10

Francois T.


People also ask

How do you use mock exception in Python?

Just assign the exception to side_effect instead: mockedObj. raiseError. side_effect = Exception("Test") . You don't have to no: and his edit has a third way of doing it where he is making a Mock with the side effect set, but its still a valid, and good thing to know how to do in testing.

What is the difference between mock and MagicMock?

With Mock you can mock magic methods but you have to define them. MagicMock has "default implementations of most of the magic methods.". If you don't need to test any magic methods, Mock is adequate and doesn't bring a lot of extraneous things into your tests.


1 Answers

AFAIK, you have to specify the keyword argument names to use the wildcard ANY.

Another option is to assert directly on the list of calls directly using mock_calls:

with patch('subprocess.check_output') as check_output:
    ... code to test here ...
    func_name, args, kwargs = check_output.mock_calls[0]

    assert func_name == 'check_output'
    assert args == [list of positional args]
    assert kwargs == {dict of keyword args} # in your case, you'd leave this out
like image 181
Elias Dorneles Avatar answered Oct 03 '22 06:10

Elias Dorneles