Search code examples
pythonunit-testingubuntuexceptioncode-coverage

How to write test case for executing except block at least once for a non-failing method in python


I have created a python class as below -

class MyClass:
    mydict = {}
    error = None
    traceback = None
    message = None

    def create_log_message(self, **kwargs):
        try:
            error = kwars.get("error", self.error)
            traceback = kwargs.get("traceback", self.traceback)
            message = kwargs.get("message", self.message)
            self.mydict = {"error": error, "traceback": traceback, "message": message}
            return self.mydict
        except Exception as e:
            error = e
            traceback = tb.format_exc()
            message = kwargs.get("message", self.message)
            self.mydict = {"error": error, "traceback": traceback, "message": message}
            return self.mydict

Below is my test class -

import unittest import TestCase
import traceback as tb
import MyClass
class TestMyClass(TestCase):
    def test_success(self):                                       # Test in case of success
        inst = MyClass()
        mydict = inst.create_log_message(message="success")
        self.assertEqual(mydict["error"], None)
        self.assertEqual(mydict["traceback"], None)
        self.assertEqual(mydict["message"], "success")
 
    def test_failure(self):                                       # test in case of exception
        try:
            1/0
        except ArithmeticError as e:
            error = e
            traceback = tb.format_exc()
            inst = MyClass()
            mydict = inst.create_log_message(error=error, traceback=traceback, message="failure")
            self.assertEqual(mydict["error"], error)
            self.assertEqual(mydict["traceback"], traceback)
            self.assertEqual(mydict["message"], "failure")

    def test_no_args(self):                                       # test for no argument being passed
        inst = MyClass()
        mydict = inst.create_log_message()
        self.assertEqual(mydict["error"], None)
        self.assertEqual(mydict["traceback"], None)
        self.assertEqual(mydict["message"], None)

    def test_extra_args(self):                                    # test for any other argument
        inst = MyClass()
        mydict = inst.create_log_message(name="test")
        with self.assertRaises(KeyError):
            self.assertEqual(mydict["name"], "test")
        self.assertEqual(mydict["error"], None)
        self.assertEqual(mydict["traceback"], None)
        self.assertEqual(mydict["message"], None)

My problem is except block in MyClass is not getting called not even once, even if I pass no arguements, matching arguments or any other/extra arguments, hence code coverage is failing(not meeting 100%), how to execute the except block via test case at least once? I am using python3.8x/ubuntu20.04.

Any help in this regard will be really helpful :)

PS: Please forgive if I have missed any details as this is my first post on stack overflow.


Solution

  • The except block is not getting executed since you have mentioned default value as None inside try block in MyClass i.e kwars.get("error", self.error).Just remove the default value and it will work.

    class MyClass:
    mydict = {}
    error = None
    traceback = None
    message = None
    
    def create_log_message(self, **kwargs):
        try:
            error = kwargs["error"]
            traceback = kwargs["traceback"]
            message = kwargs["message"]
            self.mydict = {"error": error, "traceback": traceback, "message": message}
            return self.mydict
        except Exception as e:
            error = e
            traceback = tb.format_exc()
            error = kwargs.get("error", self.error)
            traceback = kwargs.get("traceback", self.traceback)
            message = kwargs.get("message", self.message)
            self.mydict = {"error": error, "traceback": traceback, "message": message}
            return self.mydict