pythonunit-testingraiserror

Raise ValueError not getting through unit test


I am trying the unitest to raise the value error when the value is negative using the code below.

A raise error is added : number should be greater than 0 But when I run the code below:

from functools import reduce
import math
import unittest

def calculate_factorial(number):
    if number < 0:
        print('about to throw value error')
        raise ValueError('number should be greater than 0')
    elif type(number) != int:
        raise  TypeError('number should be an integer type')
    else:
        data = []
        for i in range(number):
            data.append(number - i)
            print(data)
        results = reduce((lambda x, y: x * y), data, 1)
        return results

class TestCalc(unittest.TestCase):
    def test_factorial(self):
        print('Function is starting to check for values')
        print()
        result = calculate_factorial(n)
        print('results are:',result)
        print()
        self.assertEqual(result,math.factorial(n))
        
        
    def test_n(self):
        print('The value of n taken by the class function is:',n)
        

run = True
while run:
    n = int(input('Enter an integer value: '))
    if n != -9999:
        unittest.main(argv=[''], verbosity=2, exit=False)
    else:
        run = False

I am getting the error as following. I can see below that my raise value is getting passed through but somehow the test class is not considering it.

test_factorial (__main__.TestCalc) ... ERROR
test_n (__main__.TestCalc) ... ok

======================================================================
ERROR: test_factorial (__main__.TestCalc)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "<ipython-input-3-d89c3d44c70d>", line 5, in test_factorial
    result = calculate_factorial(n)
  File "<ipython-input-2-2ad930b1e911>", line 5, in calculate_factorial
    raise ValueError('number should be greater than 0')
ValueError: number should be greater than 0

----------------------------------------------------------------------
Ran 2 tests in 0.010s

FAILED (errors=1)

Solution

  • As already mentioned in my comments, your test fails because the raised ValueError is not expected here. You can extend you test with an if to handle positive and non-positive values differently.

    class TestCalc(unittest.TestCase):
        def test_factorial(self):
            print('Function is starting to check for values')
            print()
            if n < 0:
                with self.assertRaises(ValueError) as context:
                    calculate_factorial(n)
                self.assertEqual('number should be greater than 0', str(context.exception))
            else:
                result = calculate_factorial(n)
                print('results are:', result)
                print()
                self.assertEqual(result, math.factorial(n))
    
        def test_n(self):
            print('The value of n taken by the class function is:', n)
    

    However, it could be better to have different tests for different value ranges/kinds with fixed values like this:

    class TestCalcFixedValues(unittest.TestCase):
        def test_factorial_positive(self):
            self.assertEqual(calculate_factorial(42), math.factorial(42))
    
        def test_factorial_negative(self):
            with self.assertRaises(ValueError) as context:
                calculate_factorial(-42)
            self.assertEqual('number should be greater than 0', str(context.exception))
    
        def test_factorial_NaN(self):
            with self.assertRaises(TypeError) as context:
                calculate_factorial("NaN")
            self.assertEqual('number should be an integer type', str(context.exception))
    

    (then you will see, that calculate_factorial has a bug ;))