Unittest for a function throws an exception in Python - python-3.x

class Kill_Tasks:
def __init__(self):
self.action = None
self.cmd=[]
def kill_tasks(self):
self.action = False
#exp task = chrome.exe
target = 'chrome.exe'
try:
self.cmd = suprocess.run(['taskkill','/im', target,'/f'],capture_output=True, check=True)
self.action = True
except subprocess.CalledProcessError as e:
print(e)
self.action = False
return self.cmd
Unit Test for a function throws an exception in Python.
The question is: how can I do the Unit Testing for the exception part. I'm doing Code Coverage for this function. But I am not able to check the exception because it's always True. Do I need to do a fake connection to be able to test the exception? Please help me out! Thanks

You should use unittest.mock.Mock.side_effect to mock a raised exception.
E.g.
kill_tasks.py:
import subprocess
class Kill_Tasks:
def __init__(self):
self.action = None
self.cmd = []
def kill_tasks(self):
self.action = False
# exp task = chrome.exe
target = 'chrome.exe'
try:
self.cmd = subprocess.run(['taskkill', '/im', target, '/f'], capture_output=True, check=True)
self.action = True
except subprocess.CalledProcessError as e:
print(e)
self.action = False
return self.cmd
test_kill_tasks.py:
import unittest
from unittest.mock import patch
from subprocess import CompletedProcess, CalledProcessError
from kill_tasks import Kill_Tasks
class TestKillTasks(unittest.TestCase):
#patch('kill_tasks.subprocess.run')
def test_kill_tasks_success(self, mock_run):
mock_run.return_value = CompletedProcess(args=['taskkill', '/im', 'chrome.exe', '/f'], returncode=0)
kill_tasks_instance = Kill_Tasks()
cmd = kill_tasks_instance.kill_tasks()
mock_run.assert_called_once_with(['taskkill', '/im', 'chrome.exe', '/f'], capture_output=True, check=True)
self.assertIsInstance(cmd, CompletedProcess)
self.assertTrue(kill_tasks_instance.action)
#patch('kill_tasks.subprocess.run')
def test_kill_tasks_exception(self, mock_run):
mock_run.side_effect = CalledProcessError(returncode=1, cmd='123')
kill_tasks_instance = Kill_Tasks()
kill_tasks_instance.kill_tasks()
self.assertFalse(kill_tasks_instance.action)
if __name__ == '__main__':
unittest.main()
unit test result:
coverage run /Users/dulin/workspace/github.com/mrdulin/python-codelab/src/stackoverflow/66848842/test_kill_tasks.py && coverage report -m --include='./src/**'
Command '123' returned non-zero exit status 1.
..
----------------------------------------------------------------------
Ran 2 tests in 0.001s
OK
Name Stmts Miss Cover Missing
-----------------------------------------------------------------------------
src/stackoverflow/66848842/kill_tasks.py 15 0 100%
src/stackoverflow/66848842/test_kill_tasks.py 21 0 100%
-----------------------------------------------------------------------------
TOTAL 36 0 100%

Related

mocking boto3 client for exceptions

I have successfully mocked boto3 client to test the positive case but unable to mock the same client for exceptions here is the code that i tried to mock the get_secret_value method of boto3 client to raise a ClientError.
class SecretsManager:
def __init__(self):
self.session = boto3.session.Session()
self.client = self.session.client(service_name='secretsmanager', region_name='region-name')
self.get_secrets()
def get_secrets(self): # no-pragma
try:
get_secret_value_response = self.client.get_secret_value(
SecretId=self.secret_name)
except ClientError as e:
if e.response['Error']['Code'] == 'DecryptionFailureException':
raise e
else:
if 'SecretString' in get_secret_value_response:
secret = get_secret_value_response['SecretString']
self.secrets_dict = json.loads(secret)
else:
decoded_binary_secret = base64.b64decode(
get_secret_value_response['SecretBinary'])
Tests:
class TestSecretsManager:
#mock.patch("boto3.session.Session")
def test_get_secrets(self, mock_session):
# Arrange
mock_session_object = mock.Mock()
mock_client = mock.Mock()
mock_client.get_secret_value.return_value = {"SecretString": '{"my-secret1": "val1"}'}
mock_session_object.client.return_value = mock_client
mock_session.return_value = mock_session_object
secrets = SecretsManager()
assert secrets is not None
assert len(secrets.secrets_dict) == 1
assert secrets.secrets_dict['my-secret1'] == 'val1'
#mock.patch("boto3.session.Session")
def test_get_secrets_exception(self, mock_session):
# Arrange
mock_session.client.get_secret_value.side_effect = ClientError(error_response={"Error": {"Code": "DecryptionFailureException"}}, operation_name='Test')
with pytest.raises(Exception) as err:
secrets = SecretsManager()
assert err['Error']['Code'] == 'DecryptionFailureException'
test 1 is passing but, test 2 is not raising ClientError. Can somebody help me where am going wrong?

Tello programming

Im trying to connect to my Tello drone with Spyder by socket but the dron dosen't send an answer back. It prints that the Tello drone refuses to enter command mode.
import socket
import threading
import time
import traceback
class Tello:
self.abort_flag = False
self.command_timeout = command_timeout
self.imperial = imperial
self.response = None
self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self.tello_address = (tello_ip, tello_port)
self.socket.bind((local_ip, local_port))
self.receive_thread = threading.Thread(target=self._receive_thread)
self.receive_thread.daemon=True
self.receive_thread.start()
if self.send_command('command') != 'OK':
raise RuntimeError('Tello rejected attempt to enter command mode')
def __del__(self):
self.socket.close()
def _receive_thread(self):
while True:
try:
self.response, ip = self.socket.recvfrom(256)
except Exception:
break
def send_command(self, command):
self.abort_flag = False
timer = threading.Timer(self.command_timeout, self.set_abort_flag)
self.socket.sendto(command.encode('utf-8'), self.tello_address)
timer.start()
while self.response is None:
if self.abort_flag is True:
raise RuntimeError('No response to command')
timer.cancel()
response = self.response.decode('utf-8')
self.response = None
return response
def set_abort_flag(self):
"""Sets self.abort_flag to True.
Used by the timer in Tello.send_command() to indicate to that a response
timeout has occurred.
"""
self.abort_flag = True

How can I catch an exception thrown in a function that I'm calling dynamically?

I got distracted and ended up writing a test framework in python. I'm struggling with a particular problem that this throws up.
During my assertion, I want to throw an exception as a way of bubbling a problem up to the run_test() method without requiring the user to have any knowledge of the framework. The problem is that when I do that, it seems that the try/catch block is not honoured.
Here is a cut down version of my fledgling framework:
# test_framework.py
import inspect
import module_containing_tests
class AssertionException(Exception):
def __init__(self, message):
self.message = message
def __str__(self):
return self.message
def run_test(test_name, test_method):
try:
print(">", test_name)
test_method()
print("Passed")
except AssertionException as error:
print("Failed")
print(str(error))
def assert_true(conditional):
if not conditional:
raise AssertionException("Expected True. Was False")
def test(func):
func.is_test = True
return func
members = inspect.getmembers(module_containing_tests)
for member in members:
if "is_test" in dir(member[1]) and not member[0] == "module_containing_tests":
run_test(member[0], member[1])
The module containing the tests will look like this:
# module_containing_tests.py
from test_framework import *
#test
def passing_test():
assert_true(1 + 2 == 3)
#test
def failing_test():
assert_true(1 + 2 == 5)
The output has all the exception stack tracing in it and it also halts the execution
λ python test_framework.py
> failing_test
Traceback (most recent call last):
File "test_framework.py", line 29, in <module>
run_test(member[0], member[1])
File "test_framework.py", line 13, in run_test
test_method()
File "C:\Git\simpy-test\module_containing_tests.py", line 9, in failing_test
assert_true(1 + 2 == 5)
File "C:\Git\simpy-test\test_framework.py", line 20, in assert_true
raise AssertionException("Expected True. Was False")
test_framework.AssertionException: Expected True. Was False
What I want is something like this:
λ python test_framework.py
> failing_test
Expected True. Was False
Failed
> passing_test
Passed
I think the issue is partly in the circular reference between the two files that might mess up with the visibility of the methods (as somehow explained here) and partly, maybe, in the approach. If you think about how many other testing framework work, you often have 3 elements, the unit to test, the testing framework and a test runner.
So if we try to split everythig folllowing that logic you end up having:
test_framework.py
# test_framework.py
class AssertionException(Exception):
pass
def test(f):
f.is_test = True
return f
def assert_true(conditional):
if not conditional:
raise AssertionException("Expected True. Was False")
test_runner.py
# test_runner.py
import inspect
import unit_test
from test_framework import AssertionException
def run_test(test_name, test_method):
try:
print(">", test_name)
test_method()
print("Passed")
except AssertionException as error:
print("Failed with AssertionException: " + str(error))
except Exception as error:
print("Failed with Exception: " + str(error))
if __name__ == "__main__":
members = inspect.getmembers(unit_test)
for member in members:
if "is_test" in dir(member[1]):
run_test(member[0], member[1])
unit_test.py
# unit_test.py
from test_framework import *
#test
def a_passing_test():
assert_true(1 + 2 == 3)
#test
def z_failing_test():
assert_true(1 + 2 == 5)
With this setup the circular dependency is removed and all the visibility context are respected and the output/behaviour is the expected one.
I hope it helps.
Not sure this is what you want but this works.
Copied from here Hide traceback unless a debug flag is set
Output:
$ ./test_framework.py
> a_passing_test
Passed
> z_failing_test
test_framework.AssertionException: Expected True. Was False
First file:
#!/usr/bin/env python3
#test_framework.py
import inspect
import module_containing_tests
import sys
class AssertionException(Exception):
def __init__(self, message):
self.message = message
def __str__(self):
return self.message
def run_test(test_name, test_method):
try:
print(">", test_name)
test_method()
print("Passed")
except AssertionException as error:
print("Failed")
print(str(error))
def assert_true(conditional):
if not conditional:
raise AssertionException("Expected True. Was False")
def test(func):
func.is_test = True
return func
sys.tracebacklimit=0
members = inspect.getmembers(module_containing_tests)
for member in members:
if "is_test" in dir(member[1]) and not member[0] == "module_containing_tests":
run_test(member[0], member[1])
second file:
#!/usr/bin/env python3
#module_containing_tests.py
from test_framework import *
#test
def a_passing_test():
assert_true(1 + 2 == 3)
#test
def z_failing_test():
assert_true(1 + 2 == 5)

self.assertTrue throwing traceback error in Python 3.x unittesting

I am running a small unittest to check the roman number converter. Here is my code :-
class RomConverter(object):
def __init__(self):
self.digital_mapping = {"M":1000, "D":500, "C":100, "L":50, "X":10, "V":5, "I":1}
def convert(self, rom_num):
value = 0
for char in rom_num:
val += self.digital_mapping[char]
return value
import unittest
class RomConverterTest(unittest.TestCase):
def settingUp(self):
print ("Creating a new RomConverter...")
self.cvt = RomConverter()
def tearDown(self):
print ("Destroying the RomConverter...")
self.cvt = None
def test_empty_num(self):
self.assertTrue(self.cvt.convert("") == 0)
self.assertFalse(self.cvt.convert("") > 0)
def test_no_rom_num(self):
self.assertRaises(TypeError,self.cvt.convert, None)
if __name__ == "__main__":
unittest.main()
But I am getting this message when I run the code :-
Traceback (most recent call last):
File "receipe2 - Copy.py", line 31, in test_empty_roman_numeral
self.assertTrue(self.cvt.convert_to_decimal("") == 0)
AssertionError: False is not true
I see two problems in your code.
First def settingUp(self): should be def setUp(self):
And the return of def convert(self, rom_num): is indented to much. In result the method does not return 0 incase of an empty string.
Here is a working version:
class RomConverter(object):
def __init__(self):
self.digital_mapping = {"M":1000, "D":500, "C":100, "L":50, "X":10, "V":5, "I":1}
def convert(self, rom_num):
value = 0
for char in rom_num:
value += self.digital_mapping[char]
return value
import unittest
class RomConverterTest(unittest.TestCase):
def setUp(self):
print ("Creating a new RomConverter...")
self.cvt = RomConverter()
def tearDown(self):
print ("Destroying the RomConverter...")
self.cvt = None
def test_empty_num(self):
self.assertTrue(self.cvt.convert("") == 0)
self.assertFalse(self.cvt.convert("") > 0)
def test_no_rom_num(self):
self.assertRaises(TypeError,self.cvt.convert, None)
if __name__ == "__main__":
unittest.main()

'Close window' button wont work when using tkinter + gobject

My tkinter application runs fine, but to implement dbus functionality I had to use gobject. Got it working and all, except that, running both tkinter's and gobject's mainloops makes the "close window" button from the standard window manager ('x' button in the window interface) not to work. :/ Everything else works fine, including resizing, minimizing/maximizing, restoring, and moving the window.
Any help is appreciated,
Thanks,
Little code snippet:
import dbus
from dbus.service import Object
from dbus.mainloop.glib import DBusGMainLoop
class TBOPlayerDBusInterface (Object):
tboplayer_instance = None
def __init__(self, tboplayer_instance):
self.tboplayer_instance = tboplayer_instance
dbus_loop = DBusGMainLoop()
bus_name = dbus.service.BusName("org.tboplayer.TBOPlayer", bus = dbus.SessionBus(mainloop = dbus_loop))
Object.__init__(self, bus_name, "/org/tboplayer/TBOPlayer")
#dbus.service.method('org.tboplayer.TBOPlayer', in_signature = 'as')
def openFiles(self, files):
self.tboplayer_instance._add_files(files)
# ***************************************
# MAIN
# ***************************************
if __name__ == "__main__":
datestring=" 28 Fev 2017"
dbusif_tboplayer = None
try:
bus = dbus.SessionBus()
bus_object = bus.get_object("org.tboplayer.TBOPlayer", "/org/tboplayer>/TBOPlayer", introspect = False)
dbusif_tboplayer = dbus.Interface(bus_object, "org.tboplayer.TBOPlayer")
except Exception, e:
print e
if dbusif_tboplayer is None:
tk.CallWrapper = ExceptionCatcher
bplayer = TBOPlayer()
TBOPlayerDBusInterface(bplayer)
def refresh_player():
bplayer.root.update()
return True
def run_gobject():
gobject.MainLoop().run()
gobject.idle_add(refresh_player)
bplayer.root.after(100, run_gobject)
bplayer.root.mainloop()
else:
if len(sys.argv[1:]) > 0:
dbusif_tboplayer.openFiles(sys.argv[1:])
exit()
I found the problem. For some reason, using tkinter's and gobject's mainloops interferes with the behavior of the WM_DELETE_WINDOW event, which I was using for saving some data before closing the program. Solved the problem by binding to the Configure event instead. And now the main method is as follows:
if __name__ == "__main__":
datestring=" 28 Fev 2017"
dbusif_tboplayer = None
try:
bus = dbus.SessionBus()
bus_object = bus.get_object("org.tboplayer.TBOPlayer", "/org/tboplayer/TBOPlayer", introspect = False)
dbusif_tboplayer = dbus.Interface(bus_object, "org.tboplayer.TBOPlayer")
except Exception, e:
print e
if dbusif_tboplayer is None:
tk.CallWrapper = ExceptionCatcher
bplayer = TBOPlayer()
TBOPlayerDBusInterface(bplayer)
gobject_loop = gobject.MainLoop()
def refresh_player():
try:
bplayer.root.update()
return True
except Exception, e:
bplayer.quit_omx()
gobject_loop.quit()
def run_gobject():
gobject_loop.run()
gobject.idle_add(refresh_player)
bplayer.root.after(100, run_gobject)
bplayer.root.mainloop()
else:
if len(sys.argv[1:]) > 0:
dbusif_tboplayer.openFiles(sys.argv[1:])
exit()

Resources