From: Yotta Meter on
With the following example:

#---------------------------------------------------------
#!/usr/bin/ruby

require "test/unit"

class TestImplArchFile < Test::Unit::TestCase

def test_loop

[0,1,2].each do |i|
assert_equal(i, 6, "Duh, #{i} is not equal to 6.")
end
end

end
#---------------------------------------------------------
I get the following output:
#---------------------------------------------------------

Loaded suite ./t
Started
F
Finished in 0.00527 seconds.

1) Failure:
test_loop(TestImplArchFile)
[./t.rb:10:in `test_loop'
./t.rb:9:in `each'
./t.rb:9:in `test_loop']:
Duh, 0 is not equal to 6.
<0> expected but was
<6>.
#---------------------------------------------------------

Is there any way I can see three errors, ie the exception
would create a failure, but not exit the def? I'd like to see
all errors in the loop. I'm not sure
#---------------------------------------------------------

1) Failure:
test_loop(TestImplArchFile)
[./t.rb:10:in `test_loop'
./t.rb:9:in `each'
./t.rb:9:in `test_loop']:
Duh, 0 is not equal to 6.
<0> expected but was
<6>.

2) Failure:
test_loop(TestImplArchFile)
[./t.rb:10:in `test_loop'
./t.rb:9:in `each'
./t.rb:9:in `test_loop']:
Duh, 1 is not equal to 6.
<1> expected but was
<6>.

3) Failure:
test_loop(TestImplArchFile)
[./t.rb:10:in `test_loop'
./t.rb:9:in `each'
./t.rb:9:in `test_loop']:
Duh, 2 is not equal to 6.
<2> expected but was
<6>.
--
Posted via http://www.ruby-forum.com/.

From: Brian Candler on
Yotta Meter wrote:
> Is there any way I can see three errors, ie the exception
> would create a failure, but not exit the def?

No, I don't think so. A failed assertion raises AssertionFailedError
which terminates your method. There are no restarts in Ruby.

You can accumulate the errors yourself:

errs = []
[0,1,2].each do |i|
errs << "Duh, #{i} is not equal to 6" unless i == 6
end
assert errs.empty?, errs.join("; ")

You can use a bit of metaprogramming to create three separate test
methods in a loop.

require 'test/unit'
class TestBase < Test::Unit::TestCase
(0..2).each do |i|
define_method("test_loop#{i}") do
assert_equal 6, i, "Duh, #{i} is not equal to 6."
end
end
end

Or for fun, even three separate test classes:

require 'test/unit'
class TestBase < Test::Unit::TestCase
CHECK = 0
def test_it
assert_equal 6, self.class::CHECK, "Duh, #{self.class::CHECK} !=
6"
end
end

klasses = []
(1..2).each do |n|
klass = Class.new(TestBase)
klass.const_set(:CHECK, n)
klasses << klass # for GC
end

That's not very pretty though.
--
Posted via http://www.ruby-forum.com/.

From: Yotta Meter on
This is really the great idea I was looking for, thanks. Obviously I'm
not comparing integers, I'm actually iterating over verilog modules in
an ASIC, and do a test for each verilog module. Most verilog modules
will pass, but there will be a few that don't, so I'd like the test to
go through all verilog modules.

Another question, is my philosophy off? I'm a little confused by the
amount of test options out there, rspec, cucumber, etc. Is there another
testing strategy I should be working with in this instance where I want
to iterate through an array of complex objects?

Thanks for not telling me to rtfm or google it.


>
> require 'test/unit'
> class TestBase < Test::Unit::TestCase
> (0..2).each do |i|
> define_method("test_loop#{i}") do
> assert_equal 6, i, "Duh, #{i} is not equal to 6."
> end
> end
> end
>
--
Posted via http://www.ruby-forum.com/.

From: Brian Candler on
Yotta Meter wrote:
> Another question, is my philosophy off? I'm a little confused by the
> amount of test options out there, rspec, cucumber, etc.

Well, they're apples and oranges to some extent. rspec is similar in
concept to Test::Unit but with a very different syntax (which I
personally dislike, so I stick to Test::Unit). But as far as I know,
assertion failures in rspec also raise exceptions and so can't continue.
There are a whole bunch of alternative test frameworks out there, but I
don't know enough about any of them to say whether they would fit your
needs better.

Cucumber works at a different layer. It sits on top of either rspec or
test/unit and lets you write tests in plain language, using regexps to
match that plain language and turn it into actual test code. But again,
if one step fails within a scenario, the remaining steps are skipped.

> Is there another
> testing strategy I should be working with in this instance where I want
> to iterate through an array of complex objects?

Apart from the ideas I gave before, you could try rescuing
Test::Unit::AssertionFailedError explicitly inside your loop, to allow
it to continue (but making a note of the failure).

Indeed, the core code for Test::Unit which handles this looks very
simple:

# Runs the individual test method represented by this
# instance of the fixture, collecting statistics, failures
# and errors in result.
def run(result)
yield(STARTED, name)
@_result = result
begin
setup
__send__(@method_name)
rescue AssertionFailedError => e
add_failure(e.message, e.backtrace)
rescue Exception
raise if PASSTHROUGH_EXCEPTIONS.include? $!.class
add_error($!)
ensure
begin
teardown
rescue AssertionFailedError => e
add_failure(e.message, e.backtrace)
rescue Exception
raise if PASSTHROUGH_EXCEPTIONS.include? $!.class
add_error($!)
end
end
result.add_run
yield(FINISHED, name)
end

So it looks like you could just call add_failure yourself and continue.
This is a private method/undocumented API, but I'd happily do that if it
gets the job done.

Here's a proof-of-concept:

require "test/unit"

class TestImplArchFile < Test::Unit::TestCase

def no_stop
yield
rescue Test::Unit::AssertionFailedError => e
add_failure(e.message, e.backtrace)
rescue Exception
raise if PASSTHROUGH_EXCEPTIONS.include? $!.class
add_error($!)
end

def test_loop
[0,1,2].each do |i|
no_stop do
assert_equal(i, 6, "Duh, #{i} is not equal to 6.")
end
end
end

end
--
Posted via http://www.ruby-forum.com/.

From: Yotta Meter on
I'm seeing some performance issues I can't seem to get around. Your
solution for creating a method was great though. I'd try the last one,
but I think I'm seeing a fundamental problem with Test::Unit.

Using the following code as the base reference:

#!/usr/bin/ruby

require "test/unit"

class TestImplArchFile < Test::Unit::TestCase
(0..10).each do |i|
(0..10).each do |j|
(0..100).each do |k|
define_method("test_i#{i}__j#{j}_k#{k}") do
flunk
end
end
end
end
end


When 'flunk' is set to flunk
Finished in 5.586734 seconds.
12221 tests, 12221 assertions, 12221 failures, 0 errors

When 'flunk' is replaced with true:
Finished in 0.482389 seconds.
12221 tests, 12221 assertions, 12221 failures, 0 errors

If I manually generate all 12k tests as individual tests in a new file,
with each one flunking:
Finished in 5.631014 seconds.
12221 tests, 12221 assertions, 12221 failures, 0 errors

The above would indicate that the problem is not with define_method, but
rather the ability of Test::Unit to handle a large number of test cases.

As a comparison, if I just print out results in a log file, I get the
awesome result:

Just using a class, no Unit::Test, not creating method, just print
method name
Finished in 0.102 seconds.

I couldn't get define_method going in a class to compare, it's a private
method in Method, and I really don't understand the Method rdoc example
using send.

Is there some sort of optimization in Test::Unit that I need to set?
Seems like something is really wrong, where is all this time going?
--
Posted via http://www.ruby-forum.com/.