Search code examples
pythonunit-testing

Implementing assertRaises unittest for class/class method


I have written a class in Python that is intialized with a few arguments.

Iam trying to write a test that check if all the arguments are int, otherwise throw TypeError.

Here is my attempt :

import unittest
from footer import Footer

class TestFooter(unittest.TestCase):

    def test_validInput(self):
        footer = Footer(4,5,1,0)
        self.assertTrue(footer.validInput())
        #attempt 1:
        footer1 = Footer("four","five",1,0)
        self.assertRaises(TypeError, footer1.validInput())
        #attempt 2:
        with self.assertRaises(TypeError):
            Footer("four",5,1,0)

if __name__ == '__main__':
    unittest.main()

However, this will not work. I don't understand why.

Here is the class, I'am writting the test for:

class Footer:
    def __init__(self, current_page: int, total_pages: int, boundaries: int, around: int):
        self.current_page = current_page
        self.total_pages = total_pages
        self.boundaries = boundaries
        self.around = around
        try:
            if (self.validInput()):
                footer = self.createFooter()
                self.addEllipsis(footer)
        except Exception as e:
            print(f"\nError while initializing Footer Class ({e.__class__}).\n Please fix the following: ", e)
        
    def validInput(self) -> bool:
        if (type(self.total_pages) != int or type(self.boundaries) != int or type(self.around) != int or type(self.current_page) != int ):
            raise TypeError("Invalid input. All the arguments must be of type int.")
        if (self.total_pages < 0 or self.boundaries < 0 or self.around < 0 or self.current_page < 0):
            raise ValueError("Invalid values. Please do not provide negative values.")
        if (self.current_page > self.total_pages):
            raise ValueError("Current page must be within the total number of pages")
        return True

    def createFooter(self) -> list:
        footer = []
        for page in range(1, self.total_pages + 1):
            if (page <= self.boundaries):
                footer.append(page)
            elif (page > self.total_pages-self.boundaries):
                footer.append(page)
            elif (page == self.current_page):
                footer.append(page)
            elif ((page > self.current_page and page <= (self.current_page + self.around)) or (page < self.current_page and page >= self.current_page - self.around)):
                footer.append(page)
        return footer

    def addEllipsis(self, footer: list) -> None:
        final_footer = [] 
        i = 0
        for page in footer:
            try :
                final_footer.append(page)
                if(footer[i + 1] - footer[i] > 1):
                    final_footer.append("...")
            except IndexError:
                break
            i += 1
        print("\n", ' '.join(str(page) for page in final_footer))


Here is the output for the test :

enter image description here


Solution

  • This is the wrong way to use assertRaises:

    import unittest
    
    
    def this_func_raises():
        raise ValueError
    
    
    class TestClass(unittest.TestCase):
        def test1(self):
            self.assertRaises(ValueError, this_func_raises())
    

    Note that the ValueError will be raised if you include the (), since that would execute this_func_raises and the exception will not be caught.

    And this is the right way:

    import unittest
    
    
    def this_func_raises():
        raise ValueError
    
    
    class TestClass(unittest.TestCase):
        def test1(self):
            self.assertRaises(ValueError, this_func_raises)
    

    Note that there are several other problems in your code. For example this:

    with self.assertRaises(TypeError):
        Footer("four", 5, 1, 0)
    

    Should be like so:

    with self.assertRaises(TypeError):
        Footer("four", 5, 1, 0).validInput()
    

    Lastly, you need to replace self.createFooter() with a pass until you implement it, or else you'll get another error.


    This is how your code should look like in order to pass the tests:

    class Footer:
        def __init__(self, current_page: int, total_pages: int, boundaries: int, around: int):
            self.current_page = current_page
            self.total_pages = total_pages
            self.boundaries = boundaries
            self.around = around
            try:
                if (self.validInput()):
                    # self.createFooter()
                    pass
            except Exception as e:
                print(f"\nError while initializing Footer Class ({e.__class__}).\n Please fix the following: ", e)
    
        def validInput(self) -> bool:
            if (type(self.total_pages) != int or type(self.boundaries) != int or type(self.around) != int or type(
                    self.current_page) != int):
                raise TypeError("Invalid input. All the arguments must be of type int.")
            if (self.total_pages < 0 or self.boundaries < 0 or self.around < 0 or self.current_page < 0):
                raise ValueError("Invalid values. Please do not provide negative values.")
            if (self.current_page > self.total_pages):
                raise ValueError("Current page must be within the total number of pages")
            return True
    

    test file:

    import unittest
    
    
    class TestFooter(unittest.TestCase):
    
        def test_validInput(self):
            footer = Footer(4, 5, 1, 0)
            self.assertTrue(footer.validInput())
            # attempt 1:
            footer1 = Footer("four", "five", 1, 0)
            self.assertRaises(TypeError, footer1.validInput)
            # attempt 2:
            with self.assertRaises(TypeError):
                Footer("four", 5, 1, 0).validInput()
    
    if __name__ == '__main__':
        unittest.main()