# Asserts in aggregate objects called by a Test::Unit::TestCase

**URL:** <https://rubytalk.org/t/asserts-in-aggregate-objects-called-by-a-test-unit-testcase/27326>\
**Category:** ruby-talk\
**Created:** [10 May 2006 17:31 UTC](https://rubytalk.org/t/asserts-in-aggregate-objects-called-by-a-test-unit-testcase/27326 "2006-05-10T17:31:29Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![Andrew\_Tanner](https://avatars.discourse-cdn.com/v4/letter/a/8dc957/32.png) [@Andrew\_Tanner](https://rubytalk.org/u/Andrew_Tanner)\
**Post date:** [10 May 2006 17:31 UTC](https://rubytalk.org/t/asserts-in-aggregate-objects-called-by-a-test-unit-testcase/27326/1 "2006-05-10T17:31:29Z")

</div>

Howdy Rubyists,

I'm building a framework for automating tests so I've been sinking my  
teeth into Test::Unit pretty heavily. Right now I'm trying to  
automagically do a bunch of asserts in a sub object called by a  
Test::Unit::TestCase subclass similar to something like this...

require "test/unit"

class TestStuff \< Test::Unit::TestCase

&nbsp;&nbsp;&nbsp;def test\_stuff

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;obj = SubAssertObj.new

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;obj.verify\_stuff("please\_work")

&nbsp;&nbsp;&nbsp;end

end

class SubAssertObj

&nbsp;&nbsp;&nbsp;&nbsp;import Test::Unit::Assertions

&nbsp;&nbsp;&nbsp;&nbsp;def verify\_stuff(str)

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assert\_equal("please\_work", str)

&nbsp;&nbsp;&nbsp;&nbsp;end

end

Now if the assert\_equal fails it throws the  
Test::Unit::AssertionFailedError like expected and it reports it very  
nicely in the output. However if the assert is successful in the output  
from Test::Unit I get

1 tests, 0 assertions, 0 failures, 0 errors

How can I get the assertions in the sub object to be reflected in the  
report from Test::Unit?

Thanks,

Andrew

---

<div class="post-metadata">

**Author:** ![Eric\_Hodel1](https://avatars.discourse-cdn.com/v4/letter/e/a9adbd/32.png) [@Eric\_Hodel1](https://rubytalk.org/u/Eric_Hodel1)\
**Post date:** [10 May 2006 17:45 UTC](https://rubytalk.org/t/asserts-in-aggregate-objects-called-by-a-test-unit-testcase/27326/2 "2006-05-10T17:45:35Z")

</div>

> Howdy Rubyists,
> 
> I'm building a framework for automating tests so I've been sinking my  
> teeth into Test::Unit pretty heavily. Right now I'm trying to  
> automagically do a bunch of asserts in a sub object called by a  
> Test::Unit::TestCase subclass similar to something like this...
> 
> require "test/unit"
> 
> class TestStuff \< Test::Unit::TestCase
> 
> &nbsp;&nbsp;&nbsp;def test\_stuff  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;obj = SubAssertObj.new  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;obj.verify\_stuff("please\_work")  
> &nbsp;&nbsp;&nbsp;end
> 
> end
> 
> class SubAssertObj
> 
> &nbsp;&nbsp;&nbsp;&nbsp;import Test::Unit::Assertions
> 
> &nbsp;&nbsp;&nbsp;&nbsp;def verify\_stuff(str)  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assert\_equal("please\_work", str)  
> &nbsp;&nbsp;&nbsp;&nbsp;end
> 
> end
> 
> Now if the assert\_equal fails it throws the  
> Test::Unit::AssertionFailedError like expected and it reports it very  
> nicely in the output. However if the assert is successful in the output  
> from Test::Unit I get
> 
> 1 tests, 0 assertions, 0 failures, 0 errors

See add\_assertion in Test::Unit::TestCase and Test::Unit::Assertions

> How can I get the assertions in the sub object to be reflected in the  
> report from Test::Unit?

Why not write it like this:

class TestStuff \< Test::Unit::TestCase

&nbsp;&nbsp;&nbsp;def test\_stuff  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;util\_verify\_stuff 'please work'  
&nbsp;&nbsp;&nbsp;end

&nbsp;&nbsp;&nbsp;def util\_verify\_stuff(str)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assert\_equal 'please work', str  
&nbsp;&nbsp;&nbsp;end

end

And then use subclassing to reuse common functionality?

> **···**
>
> On May 10, 2006, at 10:31 AM, Andrew Tanner wrote:
> 
> --  
> Eric Hodel - drbrain@segment7.net - [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:** ![Bret\_Pettichord](https://avatars.discourse-cdn.com/v4/letter/b/9fc348/32.png) [@Bret\_Pettichord](https://rubytalk.org/u/Bret_Pettichord)\
**Post date:** [11 May 2006 19:55 UTC](https://rubytalk.org/t/asserts-in-aggregate-objects-called-by-a-test-unit-testcase/27326/3 "2006-05-11T19:55:02Z")

</div>

I finally figured out how to do this this week. This problem has been  
nagging me for two years.

Sooner or later, when you build a Ruby testing framework of a certain  
degree of complexity, it seems to stop counting your assertions. So  
when you run the tests, you are incorrectly told you have no  
assertions. This is really annoying and makes you look like an idiot.  
What kind of tester doesn't put any verification in his tests? When  
things are still working, it looks like this:

&nbsp;&nbsp;Finished in 10.285 seconds.  
&nbsp;&nbsp;6 tests, 8 assertions, 0 failures, 0 errors

But then you get 0 assertions, even though you know your assertions are  
actually being executed. Why? (And if you look closely, you'll see they  
do get counted when they fail!)

The problem typically comes when you put assertions in your library  
modules. This isn't hard. All you have to do is put include  
Test::Unit::Assertions in your module or helper class and then you can  
include calls to assert, assert\_equal and all the other assert methods.  
It works, except that your assertions aren't counted.

The reason why is that the method add\_assertion does the counting. This  
is automatically called by all the assert methods. When they call the  
add\_assertion method of TestCase, the count shows up in your test  
results no problem. But the add\_assertion method of the Assertions  
module is just a no op. This is why they don't affect the assertion  
count. The solution is to add a functional add\_assertion method back to  
your helper module/class that ties back to your test case.

Here's how. The first thing is to keep track of the test case that is  
running. We'll just put it in a global variable, which is ugly, but it  
works. The best place to put this is in the setup method of your test  
case.

&nbsp;&nbsp;def setup  
&nbsp;&nbsp;&nbsp;&nbsp;$testcase = self  
&nbsp;&nbsp;end

The test case is actually the object the setup method is part of, so  
self gives us a reference to it when it runs. You may already have  
other stuff in your setup method as well. That's fine; just add this  
too.

Now we need to make a change to your helper class/module where you did  
the include Test::Unit::Assertions. Add this method:

&nbsp;&nbsp;def add\_assertion  
&nbsp;&nbsp;&nbsp;&nbsp;$testcase.add\_assertion  
&nbsp;&nbsp;end

The name for what we are doing here is "delegation," except that we are  
doing it in a totally non-object-oriented way. We are "delegating" the  
call to add\_assertion back to the test case where it belongs. After  
you've made these changes, tell your developer friends that you fixed  
the assertion count problem by delegating the call to add\_assertion  
back to the test case. They'll be impressed.

But don't start bragging yet. If you run your code right now, you'll  
get a complaint that you are calling a private method. I've seen some  
clever hacks to get around this problem, but actually Ruby makes the  
solution really easy. Just make the method public! Add this code to  
your TestCase class definition:

&nbsp;&nbsp;public :add\_assertion

Try doing that in Java! Don't put in any of the methods; just put it  
inside the class definition. To recap, your test case should now look  
something like this:

&nbsp;&nbsp;class MyTest \< Test::Unit::TestCase  
&nbsp;&nbsp;&nbsp;&nbsp;def setup  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$testcase = self  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# other stuff maybe  
&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;&nbsp;public :add\_assertion  
&nbsp;&nbsp;&nbsp;&nbsp;def test\_something  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# your actual tests...

---

<div class="post-metadata">

**Author:** ![Ryan\_Leavengood](https://avatars.discourse-cdn.com/v4/letter/r/a587f6/32.png) [@Ryan\_Leavengood](https://rubytalk.org/u/Ryan_Leavengood)\
**Post date:** [11 May 2006 20:13 UTC](https://rubytalk.org/t/asserts-in-aggregate-objects-called-by-a-test-unit-testcase/27326/4 "2006-05-11T20:13:10Z")

</div>

Interesting idea. Here is another possibility:

require 'test/unit'

module TestHelper  
&nbsp;&nbsp;include Test::Unit::Assertions

&nbsp;&nbsp;def initialize(test)  
&nbsp;&nbsp;&nbsp;&nbsp;@test = test  
&nbsp;&nbsp;end

&nbsp;&nbsp;def add\_assertion  
&nbsp;&nbsp;&nbsp;&nbsp;@test.send(:add\_assertion)  
&nbsp;&nbsp;end  
end

class MyTestHelper  
&nbsp;&nbsp;include TestHelper

&nbsp;&nbsp;def test\_x  
&nbsp;&nbsp;&nbsp;&nbsp;assert(true)  
&nbsp;&nbsp;end  
end

class TC\_Delegate \< Test::Unit::TestCase  
&nbsp;&nbsp;def test\_delegating  
&nbsp;&nbsp;&nbsp;&nbsp;MyTestHelper.new(self).test\_x  
&nbsp;&nbsp;end  
end  
\_\_END\_\_

Using send gets around the private problem (though that isn't  
future-proof.) I think passing in the test is better than using a  
global. Plus if you just include the TestHelper module to make use of  
this, which results in less duplicate code than your solution. There  
is probably an even slicker way to do this...

Ryan

> **···**
>
> On 5/11/06, bpettichord@gmail.com \<bpettichord@gmail.com\> wrote:
> 
> > I finally figured out how to do this this week. This problem has been  
> > nagging me for two years.
> > 
> > Sooner or later, when you build a Ruby testing framework of a certain  
> > degree of complexity, it seems to stop counting your assertions. So  
> > when you run the tests, you are incorrectly told you have no  
> > assertions. This is really annoying and makes you look like an idiot.  
> > What kind of tester doesn't put any verification in his tests? When  
> > things are still working, it looks like this:
> > 
> > &nbsp;&nbsp;Finished in 10.285 seconds.  
> > &nbsp;&nbsp;6 tests, 8 assertions, 0 failures, 0 errors
> > 
> > But then you get 0 assertions, even though you know your assertions are  
> > actually being executed. Why? (And if you look closely, you'll see they  
> > do get counted when they fail!)
> > 
> > The problem typically comes when you put assertions in your library  
> > modules. This isn't hard. All you have to do is put include  
> > Test::Unit::Assertions in your module or helper class and then you can  
> > include calls to assert, assert\_equal and all the other assert methods.  
> > It works, except that your assertions aren't counted.
> > 
> > The reason why is that the method add\_assertion does the counting. This  
> > is automatically called by all the assert methods. When they call the  
> > add\_assertion method of TestCase, the count shows up in your test  
> > results no problem. But the add\_assertion method of the Assertions  
> > module is just a no op. This is why they don't affect the assertion  
> > count. The solution is to add a functional add\_assertion method back to  
> > your helper module/class that ties back to your test case.
> > 
> > Here's how. The first thing is to keep track of the test case that is  
> > running. We'll just put it in a global variable, which is ugly, but it  
> > works. The best place to put this is in the setup method of your test  
> > case.
> > 
> > &nbsp;&nbsp;def setup  
> > &nbsp;&nbsp;&nbsp;&nbsp;$testcase = self  
> > &nbsp;&nbsp;end
> > 
> > The test case is actually the object the setup method is part of, so  
> > self gives us a reference to it when it runs. You may already have  
> > other stuff in your setup method as well. That's fine; just add this  
> > too.
> > 
> > Now we need to make a change to your helper class/module where you did  
> > the include Test::Unit::Assertions. Add this method:
> > 
> > &nbsp;&nbsp;def add\_assertion  
> > &nbsp;&nbsp;&nbsp;&nbsp;$testcase.add\_assertion  
> > &nbsp;&nbsp;end
> > 
> > The name for what we are doing here is "delegation," except that we are  
> > doing it in a totally non-object-oriented way. We are "delegating" the  
> > call to add\_assertion back to the test case where it belongs. After  
> > you've made these changes, tell your developer friends that you fixed  
> > the assertion count problem by delegating the call to add\_assertion  
> > back to the test case. They'll be impressed.
> > 
> > But don't start bragging yet. If you run your code right now, you'll  
> > get a complaint that you are calling a private method. I've seen some  
> > clever hacks to get around this problem, but actually Ruby makes the  
> > solution really easy. Just make the method public! Add this code to  
> > your TestCase class definition:
> > 
> > &nbsp;&nbsp;public :add\_assertion
> > 
> > Try doing that in Java! Don't put in any of the methods; just put it  
> > inside the class definition. To recap, your test case should now look  
> > something like this:
> > 
> > &nbsp;&nbsp;class MyTest \< Test::Unit::TestCase  
> > &nbsp;&nbsp;&nbsp;&nbsp;def setup  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$testcase = self  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# other stuff maybe  
> > &nbsp;&nbsp;&nbsp;&nbsp;end  
> > &nbsp;&nbsp;&nbsp;&nbsp;public :add\_assertion  
> > &nbsp;&nbsp;&nbsp;&nbsp;def test\_something  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# your actual tests...

---

<div class="post-metadata">

**Author:** ![Eric\_Hodel1](https://avatars.discourse-cdn.com/v4/letter/e/a9adbd/32.png) [@Eric\_Hodel1](https://rubytalk.org/u/Eric_Hodel1)\
**Post date:** [11 May 2006 21:19 UTC](https://rubytalk.org/t/asserts-in-aggregate-objects-called-by-a-test-unit-testcase/27326/5 "2006-05-11T21:19:39Z")

</div>

I've never needed to have all this complexity to reuse test methods.

Making abstract Test::Unit::TestCase subclasses is much simpler than dispatching to some module.

> **···**
>
> On May 11, 2006, at 1:13 PM, Ryan Leavengood wrote:
> 
> > On 5/11/06, bpettichord@gmail.com \<bpettichord@gmail.com\> wrote:
> > 
> > > To recap, your test case should now look  
> > > something like this:
> > > 
> > > &nbsp;&nbsp;class MyTest \< Test::Unit::TestCase  
> > > &nbsp;&nbsp;&nbsp;&nbsp;def setup  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$testcase = self  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# other stuff maybe  
> > > &nbsp;&nbsp;&nbsp;&nbsp;end  
> > > &nbsp;&nbsp;&nbsp;&nbsp;public :add\_assertion  
> > > &nbsp;&nbsp;&nbsp;&nbsp;def test\_something  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# your actual tests...
> > 
> > Interesting idea. Here is another possibility:
> > 
> > require 'test/unit'
> > 
> > module TestHelper  
> > include Test::Unit::Assertions
> > 
> > def initialize(test)  
> > &nbsp;&nbsp;&nbsp;@test = test  
> > end
> > 
> > def add\_assertion  
> > &nbsp;&nbsp;&nbsp;@test.send(:add\_assertion)  
> > end  
> > end
> > 
> > class MyTestHelper  
> > include TestHelper
> > 
> > def test\_x  
> > &nbsp;&nbsp;&nbsp;assert(true)  
> > end  
> > end
> > 
> > class TC\_Delegate \< Test::Unit::TestCase  
> > def test\_delegating  
> > &nbsp;&nbsp;&nbsp;MyTestHelper.new(self).test\_x  
> > end  
> > end  
> > \_\_END\_\_
> > 
> > Using send gets around the private problem (though that isn't  
> > future-proof.) I think passing in the test is better than using a  
> > global. Plus if you just include the TestHelper module to make use of  
> > this, which results in less duplicate code than your solution. There  
> > is probably an even slicker way to do this...
> 
> --  
> Eric Hodel - drbrain@segment7.net - [http://blog.segment7.net](http://blog.segment7.net)  
> This implementation is HODEL-HASH-9600 compliant
> 
> [http://trackmap.robotcoop.com](http://trackmap.robotcoop.com)
