How to interrupt unit tests if a library is not present

Hi all,

I am developing support for PhyloXML in BioRuby as Google Summer of Code
project. I have a question about unit testing.

My code depends on libxml-ruby library (other parts of BioRuby does
not). So
I want to test if libxml-ruby is required and then if it is not, i want
to
quit my unit test suite (a file tes_phyloxml.rb) nicely (don’t perform
any
unit tests related to phyloxml since they anyways gonna fail) but the
rest
of unit test suites should continue running.

Right now the it completely exits, if can’t load xml library, but I
would
like the other tests to continue running.

#First let’s test if xml library is here, since it will be required by
bio/db/phyloxml
begin
require ‘xml’
rescue LoadError
puts "Please install libxml-ruby library. It is needed for
Bio::PhyloXML
module. Unit tests will exit now.
exit 1
end

require ‘bio/db/phyloxml’

class TestPhyloXML1 < Test::Unit::TestCase

 def setup
  @phyloxml = Bio::PhyloXML.new(TestPhyloXMLData.example_xml)
end

def test_init
  assert_equal(@phyloxml.class, Bio::PhyloXML)
end

#[…]

end

Thanks,

Diana

Hi –

On Tue, 30 Jun 2009, Diana J. wrote:

exit 1

def test_init
assert_equal(@phyloxml.class, Bio::PhyloXML)
end

#[…]

end

Maybe something like this, if it’s not too convoluted:

no_xml = false

begin
require ‘xml’
rescue LoadError
puts “No libxml; not running those tests…” # or whatever
no_xml = true
end

unless no_xml
class TestPhyloXML1

etc.

David

Thanks a lot! It worked like a charm!

Diana

On Tue, 30 Jun 2009, David A. Black wrote:

begin
require “xml”
rescue LoadError
puts “No xml library…”
else
class TestPhyloXML1 < Test::Unit::TestCase

end
end

OK, third time a charm.

begin
require ‘xml’
class TestPhyloXML1 < Test::Unit::TestCase

end
rescue LoadError
puts “No xml library…”
end

I think that’s as compact and streamlined as I can get it :slight_smile:

David

Hi –

On Tue, 30 Jun 2009, Diana J. wrote:

Thanks a lot! It worked like a charm!

Rob B., in another context, reminded me that
exception-handling blocks can have an “else” clause. So you could do
the slightly simpler:

begin
require “xml”
rescue LoadError
puts “No xml library…”
else
class TestPhyloXML1 < Test::Unit::TestCase

end
end

David

On Mon, Jun 29, 2009 at 4:07 PM, David A. Black [email protected]
wrote:

exception-handling blocks can have an “else” clause. So you could do
end
puts “No xml library…”
Ruby/Rails consulting & training: http://www.rubypal.com
Now available: The Well-Grounded Rubyist (The Well-Grounded Rubyist)
“Ruby 1.9: What You Need To Know” Envycasts with David A. Black
http://www.envycasts.com

Yes indeed! Thanks!

Diana

Diana J. [email protected] wrote:

Thanks a lot! It worked like a charm!
else
class TestPhyloXML1 < Test::Unit::TestCase

end
rescue LoadError
puts “No xml library…”
end

I think that’s as compact and streamlined as I can get it :slight_smile:

Indeed - quite a while ago I wrote myself a utility for requiring
without penalty in case of failure, and here it is (as you’ll see, it
looks like a mere generalization of what David Black has already shown):

def myrequire(*what)
catch NameError
what.each do |thing|
begin
require((t = Array(thing))[0])
Array(t[1]).each {|inc| include self.class.const_get(inc)}
rescue LoadError
puts "Failed to locate required "#{thing}". "
puts $!
end
end
end

Here are some usage notes:

(1) no penalty for failure; we catch the LoadError and we don’t re-raise

(2) arg can be an array, so multiple requires can be combined in one
line

(3) array element itself can be a pair, in which case second must be
array of desired includes as symbols; that way, we don’t try to perform
the includes unless the require succeeded (and if an include fails, that
does raise all the way since we don’t catch NameError)

So, you might say e.g.

myrequire “pathname”, “yaml”, “erb”, “pp”, “uri”, “rubygems”, “exifr”

Or (an example with an include):

myrequire [‘rexml/document’, :REXML]

m.