Tyler Mutai
Tyler Mutai

Reputation: 115

attributeError("'_AssertRaisesContext' object has no attribute 'exception'",),

I'm a beginner coding in python. I really don't understand what this error refers to. Any help will be greatly appreciated. the code is supposed to calculate the taxes of people in a certain country as follows: Yearly Income: 0 - 1000

Tax Rate: 0%

Yearly Income: 1,001 - 10,000

Tax Rate: 10%

Yearly Income: 10,001 - 20,200

Tax Rate: 15%

Yearly Income: 20,201 - 30,750

Tax Rate: 20%

Yearly Income: 30,751 - 50,000

Tax Rate: 25%

Yearly Income: Over 50,000

Tax Rate: 30%

my code:

def calculate_tax(pDict):
  if type(pDict) is dict:
    try:
      length = len(pDict)
      count = 0
      #decleration of new updated dictionary
      dict_list = {}
      while count<length:
        #calculate yearly tax
        #countdown of values in the dictionary until the last value
        totals = list(pDict.values())[count]
        totals = int(totals)
        names = list(pDict.keys())[count]
        #decleration of variable to store tax
        tTax = 0
        if totals < 1000:
          tTax = totals * 0
        elif totals > 1000 and totals<= 10000:
          tTax = 1000 * 0
          totals = totals - 1000
          tTax = tTax + totals * 0.1
        elif totals > 10000 and totals <=20200:
          tTax = 1000 * 0
          tTax = tTax + 9000 * 0.1
          totals=totals-10000
          tTax = tTax + totals * 0.15
        elif totals >20200 and totals <= 30750:
          tTax = 1000 * 0
          tTax = tTax + 9000 * 0.1
          tTax = tTax + 10200 * 0.15
          totals=totals-20200
          tTax = tTax + totals * 0.2
        elif totals>30750 and totals<=50000:
          tTax = 1000 * 0
          tTax = tTax + 9000 * 0.1
          tTax = tTax + 10200 * 0.15
          tTax = tTax + 10550 * 0.2
          totals=totals-30750
          tTax = tTax + totals * 0.25
        else:
          tTax = 1000 * 0
          tTax = tTax + 9000 * 0.1
          tTax = tTax + 10200 * 0.15
          tTax = tTax + 10550 * 0.2
          tTax = tTax + 19250 * 0.25
          totals=totals-50000
          tTax = tTax + totals * 0.3
        dict_list.setdefault(names,tTax)
        count = count + 1
      return dict_list
    except(attributeError,TypeError):
      raise ValueError('The provided input is not a dictionary')
  else:
    print("only dict type values allowed")

the code used to test if my code works:

from unittest import TestCase

    class CalculateTaxTests(TestCase):
      def test_it_calculates_tax_for_one_person(self):
        result = calculate_tax({"James": 20500})
        self.assertEqual(result, {"James": 2490.0}, msg="Should return {'James': 2490.0} for the input {'James': 20500}")

      def test_it_calculates_tax_for_several_people(self):
        income_input = {"James": 20500, "Mary": 500, "Evan": 70000}
        result = calculate_tax(income_input)
        self.assertEqual({"James": 2490.0, "Mary": 0, "Evan": 15352.5}, result,
          msg="Should return {} for the input {}".format(
                {"James": 2490.0, "Mary": 0, "Evan": 15352.5},
                {"James": 20500, "Mary": 500, "Evan": 70000}
          )
        )

      def test_it_does_not_accept_integers(self):
        with self.assertRaises(ValueError) as context:
          calculate_tax(1)
          self.assertEqual(
            "The provided input is not a dictionary.",
            context.exception.message, "Invalid input of type int not allowed"
          )

      def test_calculated_tax_is_a_float(self):
        result = calculate_tax({"Jane": 20500})
        self.assertIsInstance(
          calculate_tax({"Jane": 20500}), dict, msg="Should return a result of data type dict")
        self.assertIsInstance(result["Jane"], float, msg="Tax returned should be an float.")

      def test_it_returns_zero_tax_for_income_less_than_1000(self):
        result = calculate_tax({"Jake": 100})
        self.assertEqual(result, {"Jake": 0}, msg="Should return zero tax for incomes less than 1000")

      def test_it_throws_an_error_if_any_of_the_inputs_is_non_numeric(self):
        with self.assertRaises(ValueError, msg='Allow only numeric input'):
          calculate_tax({"James": 2490.0, "Kiura": '200', "Kinuthia": 15352.5})

      def test_it_return_an_empty_dict_for_an_empty_dict_input(self):
        result = calculate_tax({})
        self.assertEqual(result, {}, msg='Should return an empty dict if the input was an empty dict')

Please help:-)

Upvotes: 9

Views: 7531

Answers (1)

Luke Woodward
Luke Woodward

Reputation: 64989

For reference, the complete exception message from the failing test is as follows:

ERROR: test_it_does_not_accept_integers (__main__.CalculateTaxTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "calculate_tax_test.py", line 27, in test_it_does_not_accept_integers
    context.exception.message, "Invalid input of type int not allowed"
AttributeError: '_AssertRaisesContext' object has no attribute 'exception'

The failing test is this:

      def test_it_does_not_accept_integers(self):
        with self.assertRaises(ValueError) as context:
          calculate_tax(1)
          self.assertEqual(
            "The provided input is not a dictionary.",
            context.exception.message, "Invalid input of type int not allowed"
          )

The problem is that the assertion after calculate_tax is in the wrong place. If an exception is raised in calculate_tax, the assertion will be skipped. If no exception is raised, the assertion will fail. The assertion will therefore never pass.

The fix is to un-indent the assertion to move it out of the with statement. For clarity I've also inserted a blank line:

      def test_it_does_not_accept_integers(self):
        with self.assertRaises(ValueError) as context:
          calculate_tax(1)

        self.assertEqual(
          "The provided input is not a dictionary.",
          context.exception.message, "Invalid input of type int not allowed"
        )

The with self.assertRaises(...) statement can catch an exception if one gets raised by the call to calculate_tax. If this happens, the exception detail is then left in context, and your assertion would then be able to test whether the exception was as you expected.

However, even after making this change, the test still fails, because calculate_tax(1) doesn't raise a ValueError. I'll leave it up to you to fix this.

Upvotes: 18

Related Questions