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.
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
@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)
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 << ----------------------
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.
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.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With