Search code examples
rubyunit-testingtestingassertfactorial

How to use assert_raise to test for an error in Ruby?


I have the programs factorial.rb and test_factorial.rb. The former looks like this:

def factorial(n)
  (1..n).inject(:*) || 1
end

test_factorial looks like this:

def test_number
  assert_equal 6, factorial(3),"3! should be 6"
end

def test_zero
  assert_equal 1, factorial(0), "0! should be 1"
end

I need to add another method, test_negative to the test file that confirms an error is raised when the factorial is negative. I looked at the documentation but still don't understand what I'm supposed to do. Do I have to specify a certain type of error after assert_raise? Do I need to add code to factorial.rb or not since the error is generated automatically?


Solution

  • Assuming that you are using minitest, if you are trying to test that an error is raised you can use the asert_raises method. (Notice the plural form)

    def test_negative
      assert_raises <expected error name> do
        factorial(-1)
      end
    end
    

    However, no error will be raised with the example you presented so far.

    Additional information:

    • This example (1..-5).inject(:*) will evaluate to nil. You will not get an error. I assume your test_negative should assert that the return value is 1 given your current implementation.

    • Also if you would like to give inject a default value you can pass it as the first argument: (1..n).inject(1, :*). This way you avoid using the || operator.

    A great suggestion from @ArupRakshit below is to raise your own NegativeFactorial exception. You will need to define it first.

    class NegativeFactorial < StandardError; end
    

    Then you can use it in your factorial method like this:

    def factorial(n)
      raise NegativeFactorial, "The number provided is negative." if n < 0
      (1..n).inject(1, :*)
    end
    

    And you can implement your test_negative to assert that the exception has been raised.

    def test_negative
      assert_raises NegativeFactorial do
        factorial(-1)
      end
    end