Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Understanding with statement to catch ValueError in unittest class

New to unittest and Python in general, came across example in a tutorial introduction to unit testing wherein a with statement is used to catch a ValueError.

The script being tested (invoice_calculator.py) is:

def divide_pay(amount, staff_hours):
    """
    Divide an invoice evenly amongst staff depending on how many hours they
    worked on a project
    """
    total_hours = 0
    for person in staff_hours:
        total_hours += staff_hours[person]

    if total_hours == 0:
        raise ValueError("No hours entered")

    per_hour = amount / total_hours

    staff_pay = {}
    for person in staff_hours:
        pay = staff_hours[person] * per_hour
        staff_pay[person] = pay

    return staff_pay

The unit test includes this function in order to catch an edge case wherein staff_hours = None :

import unittest
from invoice_calculator import divide_pay

class InvoiceCalculatorTests(unittest.TestCase):
    def test_equality(self):
        pay = divide_pay(300.0, {"Alice": 3.0, "Bob": 6.0, "Carol": 0.0})
        self.assertEqual(pay, {'Bob': 75.0, 'Alice': 75.0, 'Carol': 150.0})

    def test_zero_hours_total(self):
        with self.assertRaises(ValueError):
            pay = divide_pay(360.0, {"Alice": 0.0, "Bob": 0.0, "Carol": 0.0})

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

Regarding the use of the with statement in test_zero_hours_total(self), what is actually happening here in terms of how this statement works/is being executed?

Is the test_zero_hours_total() function basically working as follows (layman's description): the expected error should be ValueError (which we're doing by passing ValueError to the function assertRaises()) when 360.0, {"Alice": 0.0, "Bob": 0.0, "Carol": 0.0} (which would raise a ValueError in divide_pay()) is passed as arguments to the divide_pay() function?

like image 957
AdjunctProfessorFalcon Avatar asked Dec 16 '15 23:12

AdjunctProfessorFalcon


People also ask

Which of the following component would you use to set up the execution of tests and provides the outcome to the user?

A test runner is a component which set up the execution of tests and provides the outcome to the user.

What is assertRaises?

assertraises is a function that fails unless an exception is raised by an object of a class. It is mostly used in testing scenarios to prevent our code from malfunctioning. Let's work with a detailed example to see the working of assertRaises .

How do you write test cases for exceptions in Python?

There are two ways you can use assertRaises: using keyword arguments. Just pass the exception, the callable function and the parameters of the callable function as keyword arguments that will elicit the exception. Make a function call that should raise the exception with a context.


1 Answers

I'm not 100% sure what your question is here ...

TestCase.assertRaises creates an object that can be used as a context manager (which is why it can be used with the with statement). When used this way:

with self.assertRaises(SomeExceptionClass):
    # code

The context manager's __exit__ method will check the exception information passed in. If it is missing, an AssertionError will be thrown causing the test to fail. If the exception is the wrong type (e.g. not an instance of SomeExceptionClass), an AssertionError will be thrown as well.

like image 189
mgilson Avatar answered Nov 15 '22 22:11

mgilson