# Assert\_raise question

**URL:** <https://www.ruby-forum.com/t/assert-raise-question/54578>\
**Category:** Ruby\
**Created:** [March 8, 2006, 10:43pm UTC](https://www.ruby-forum.com/t/assert-raise-question/54578 "2006-03-08T22:43:20Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![smc7000](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/ed655f/32.png) [@smc7000](https://www.ruby-forum.com/u/smc7000)\
**Post date:** [March 8, 2006, 10:43pm UTC](https://www.ruby-forum.com/t/assert-raise-question/54578/1 "2006-03-08T22:43:20Z")

</div>

Currently, assert\_raise expects you to know exactly what kind of  
exception  
is going  
to be thrown by raise. Basically it tests to see if exception.class ==  
expected.class.  
I think a more appropriate behavior would be to test  
exception.kind\_of?expected. I  
would also be happy if there were one method that performed the way it  
does  
currently  
and another that checks exception parentage.

Please see the code below for an example of two tests. I think both  
should  
pass but  
only the first test does because ArgumentError != StandardError.

Sean C.

### Begin test.rb

require ‘test/unit’  
class TestRaise \< Test::Unit::TestCase  
def test\_raise  
assert\_raise(ArgumentError){raise ArgumentError.new(“basic argument  
issue”)}  
end  
def test\_raise\_parent  
assert\_raise(StandardError){raise ArgumentError.new(“basic argument  
issue”)}  
end  
end

### End test.rb

> ruby test.rb  
> Loaded suite test  
> Started  
> .F  
> Finished in 0.018356 seconds.

1. Failure:  
test\_raise\_parent(TestRaise) [test.rb:7]:  
 exception expected but was  
Class:   
Message: \<“basic argument issue”\>  
—Backtrace—  
test.rb:7:in `test_raise_parent' test.rb:7:in`test\_raise\_parent’

* * *

2 tests, 2 assertions, 1 failures, 0 errors

---

<div class="post-metadata">

**Author:** ![smc7000](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/ed655f/32.png) [@smc7000](https://www.ruby-forum.com/u/smc7000)\
**Post date:** [March 8, 2006, 10:45pm UTC](https://www.ruby-forum.com/t/assert-raise-question/54578/2 "2006-03-08T22:45:38Z")

</div>

Sean C. wrote:  
[…]

> I think a more appropriate behavior would be to test  
> exception.kind\_of?expected. I would also be happy if  
> there were one method that performed the way it  
> does currently and another that checks exception parentage.

+1

–  
– Jim W.

---

<div class="post-metadata">

**Author:** ![smc7000](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/ed655f/32.png) [@smc7000](https://www.ruby-forum.com/u/smc7000)\
**Post date:** [March 8, 2006, 11:59pm UTC](https://www.ruby-forum.com/t/assert-raise-question/54578/3 "2006-03-08T23:59:53Z")

</div>

On Mar 8, 2006, at 1:42 PM, Sean C. wrote:

> Currently, assert\_raise expects you to know exactly what kind of  
> exception  
> is going to be thrown by raise. Basically it tests to see if  
> exception.class ==  
> expected.class.
> 
> I think a more appropriate behavior would be to test  
> exception.kind\_of?expected. I would also be happy if there were  
> one method that performed the way it does currently and another  
> that checks exception parentage.

For a given input a method should only raise one class of exception.  
The restriction forces you to write better tests.

> Please see the code below for an example of two tests. I think  
> both should  
> pass but only the first test does because ArgumentError !=  
> StandardError.

require ‘socket’  
require ‘test/unit’

class MyClass  
def connect(overthere)  
unless overthere =~ /:\d+\Z/ then  
raise ArgumentError, “Use host:port, got #{overthere}”  
end  
host, port = overthere.split ‘:’  
@socket = TCPSocket.new host, port.to\_i  
end  
end

This method can raise at least two different exceptions on bad input  
so you should test for them separately. This allows consumers of  
your code to behave properly depending upon what arguments they feed  
your code.

class TestMyClass \< Test::Unit::TestCase

def setup  
@obj = MyClass.new  
end

def test\_connect\_bad\_args\_no\_port  
assert\_raises ArgumentError do  
@obj.connect ‘host’  
end  
end

def test\_connect\_bad\_args\_bad\_port  
assert\_raises ArgumentError do  
@obj.connect ‘host:port’  
end  
end

def test\_connect\_bad\_host  
assert\_raises SocketError do  
@obj.connect ‘[no-such-host.example.com:80](http://no-such-host.example.com:80)’  
end  
end

end

–  
Eric H. - removed\_email\_address@domain.invalid - [http://blog.segment7.net](http://blog.segment7.net)  
This implementation is HODEL-HASH-9600 compliant

[http://trackmap.robotcoop.com](http://trackmap.robotcoop.com)

---

<div class="post-metadata">

**Author:** ![smc7000](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/ed655f/32.png) [@smc7000](https://www.ruby-forum.com/u/smc7000)\
**Post date:** [March 9, 2006, 2:29am UTC](https://www.ruby-forum.com/t/assert-raise-question/54578/4 "2006-03-09T02:29:11Z")

</div>

Eric H. wrote:

> For a given input a method should only raise one class of exception.  
> The restriction forces you to write better tests.

The reason I would like it is that the test is the specification of the  
behavior. I often wish to specify that a method will raise a more  
general exception than the one it actually raises. The actual exception  
raised may be an implementation detail that I don’t wish to have  
expressed in the spec.

–  
– Jim W.

---

<div class="post-metadata">

**Author:** ![smc7000](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/ed655f/32.png) [@smc7000](https://www.ruby-forum.com/u/smc7000)\
**Post date:** [March 9, 2006, 6:06am UTC](https://www.ruby-forum.com/t/assert-raise-question/54578/5 "2006-03-09T06:06:12Z")

</div>

+1 again.

A big part of UT is to allow ease of refactoring. Part of refactoring  
is, IMO, making exceptions more specific (eg from raise “No record  
found” to raise DBException, “No record found”) and the like.

Having to change your UT’s when you want to refactor is a bit self  
defeating.

---

<div class="post-metadata">

**Author:** ![smc7000](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/ed655f/32.png) [@smc7000](https://www.ruby-forum.com/u/smc7000)\
**Post date:** [November 20, 2006, 11:58pm UTC](https://www.ruby-forum.com/t/assert-raise-question/54578/6 "2006-11-20T23:58:56Z")

</div>

unknown wrote:

> +1 again.
> 
> A big part of UT is to allow ease of refactoring. Part of refactoring  
> is, IMO, making exceptions more specific (eg from raise “No record  
> found” to raise DBException, “No record found”) and the like.
> 
> Having to change your UT’s when you want to refactor is a bit self  
> defeating.

Agreed.

Another +1. The whole point of having an exception hierarchy is so that  
you can specify a parent exception class at the interface level. You do  
this so that as your software grows, you can add new sub-exceptions  
without breaking your unit tests or your client’s code. Sometimes you  
are interested in the actual exception, but sometimes you just want to  
catch the more general exception and don’t care what the specific class  
is.

Here’s an example:

begin  
eval(some text)  
rescue ScriptError =\> e

# Handle the script error

end

Do we always care if it was a ScriptError descendant (shown below)?

LoadError  
NotImplementedError  
SyntaxError

No. Not always. Maybe not even in a unit test. Maybe the unit test  
starts off more general, and then as time goes by gets refined to test  
the exact exceptions.

I believe it’s better to allow the users of general library code to use  
it the way that suits them best. So, I suggest adding another assertion  
method, assert\_raise\_s, which will succeed if the argument class of the  
raised exception is derived from (\<=) the expected class. That way, you  
can have both a strict assertion (assert\_raise) and the more general  
case (assert\_raise\_s).

In the meantime, I will just add a local assert\_raise\_s because, thanks  
to Matz, Ruby classes are open to extension.

---

<div class="post-metadata">

**Author:** ![smc7000](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/ed655f/32.png) [@smc7000](https://www.ruby-forum.com/u/smc7000)\
**Post date:** [June 2, 2010, 10:49pm UTC](https://www.ruby-forum.com/t/assert-raise-question/54578/7 "2010-06-02T22:49:35Z")

</div>

+1 also.

It might make sense to define:  
assert\_something\_raised  
to parallel the existing  
assert\_nothing\_raised

- ff

---

<div class="post-metadata">

**Author:** ![smc7000](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/ed655f/32.png) [@smc7000](https://www.ruby-forum.com/u/smc7000)\
**Post date:** [June 3, 2010, 5:01pm UTC](https://www.ruby-forum.com/t/assert-raise-question/54578/8 "2010-06-03T17:01:10Z")

</div>

On Thu, Mar 9, 2006 at 3:29 AM, Jim W. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
wrote:

> –  
> – Jim W.

There is no way you are wrong, thus you are both right :P.  
Personally I prefer rspec’s behavior, also because it matches the  
semantics of “rescue”.  
But I would like to raise a question myself - I just broke the record  
for the cheapest pun - why not have two different assertions for being  
able to test/specify two different things.

Cheers  
R.

---

<div class="post-metadata">

**Author:** ![smc7000](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/ed655f/32.png) [@smc7000](https://www.ruby-forum.com/u/smc7000)\
**Post date:** [August 27, 2008, 4:28pm UTC](https://www.ruby-forum.com/t/assert-raise-question/54578/9 "2008-08-27T16:28:58Z")

</div>

[snip]

> ### Begin test.rb
> 
> require ‘test/unit’  
> class TestRaise \< Test::Unit::TestCase  
> def test\_raise  
> assert\_raise(ArgumentError){raise ArgumentError.new(“basic argument  
> issue”)}  
> end  
> def test\_raise\_parent  
> assert\_raise(StandardError){raise ArgumentError.new(“basic argument  
> issue”)}  
> end  
> end
> 
> ### End test.rb

[snip]

This is a somewhat unrelated question, but in playing around with this,  
I discovered something odd. The test\_raise method above works, but the  
following modification of it does not:

def test\_raise  
assert\_raise ArgumentError {raise ArgumentError.new(“basic argument  
issue”)}  
end

Now there’s suddenly an Exception: undefined method ‘ArgumentError’…  
I was more than a little surprised to discover that the parens make a  
difference here? Can anyone explain to me _why_ there’s a difference?

Doug

---

<div class="post-metadata">

**Author:** ![smc7000](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/ed655f/32.png) [@smc7000](https://www.ruby-forum.com/u/smc7000)\
**Post date:** [June 4, 2010, 3:54pm UTC](https://www.ruby-forum.com/t/assert-raise-question/54578/10 "2010-06-04T15:54:49Z")

</div>

Doug G. wrote:

> def test\_raise  
> assert\_raise ArgumentError {raise ArgumentError.new(“basic argument  
> issue”)}  
> end
> 
> Now there’s suddenly an Exception: undefined method ‘ArgumentError’…  
> I was more than a little surprised to discover that the parens make a  
> difference here? Can anyone explain to me _why_ there’s a difference?

foo { … } is parsed as a method call with a block.

So your code is parsed as:

assert\_raise(ArgumentError() { mode code })

Method names which start with a capital letter are fairly infrequent,  
but are allowed - see for example Integer(x) or Array(x).

Using do…end instead of {…} tips the parsing the right way:

assert\_raise ArgumentError do  
raise ArgumentError.new “basic argument issue”  
end
