Passing data to tests with test/unit


#1

I have a test case, based on the Test::Unit::TestCase. How does one pass
data to the test in such a way that the test can be run multiple times
with different input.

For example:

class TC_CreateOrder < Test::Unit::TestCase
def test_NewOrder
assert “order successful”
end
end

Now, I want to be able to generate a new order for various order types,
(TYPE1, TYPE2, TYPE3, etc.)

class TS_OrderTests
def self.suite
suite = Test::Unit::TestSuite.new
suite << TC_CreateOrder.suite # TYPE1 goes here
suite << TC_CreateOrder.suite # TYPE2 goes here
suite << TC_CreateOrder.suite # TYPE3 goes here
return suite
end
end

Test::Unit::UI::Console::TestRunner.run(TS_OrderTests)

Thanks in advance.


#2

On Thu, Mar 29, 2007 at 06:23:14AM +0900, Matt B. wrote:

end
return suite
end
end

Test::Unit::UI::Console::TestRunner.run(TS_OrderTests)

If it’s only one test method, you can factor it out in the class:

class TC_CreateOrder < Test::Unit::TestCase
def do_test(t)
… process t
end

def test_type1
do_test(TYPE1)
end

def test_type2
do_test(TYPE2)
end

def test_type3
do_test(TYPE3)
end
end

Otherwise, how about:

class TC_CreateOrder1 < TC_CreateOrder
FIXTURE = TYPE1
end

class TC_CreateOrder2 < TC_CreateOrder
FIXTURE = TYPE2
end

class TC_CreateOrder3 < TC_CreateOrder
FIXTURE = TYPE3
end

(I’m not sure how you’d prevent the base test TC_CreateOrder being run)

Regards,

Brian.


#3

Thanks Brian,

This would work ok if there was only one test method and only 3 types.
Now let’s say that I want to use this test technique multiple times,
with multiple test methods. And, the data input is over 100 items.
Duplicating this structure 100 times doesn’t seem tenable.

What I am really looking for is a data-driven test method, such that I
can use the same test case and pass it different data. However, for
test execution and measurement purposes, it is preferable to record
these as separate tests.

Brian C. wrote:

On Thu, Mar 29, 2007 at 06:23:14AM +0900, Matt B. wrote:

end
return suite
end
end

Test::Unit::UI::Console::TestRunner.run(TS_OrderTests)

If it’s only one test method, you can factor it out in the class:

class TC_CreateOrder < Test::Unit::TestCase
def do_test(t)
… process t
end

def test_type1
do_test(TYPE1)
end

def test_type2
do_test(TYPE2)
end

def test_type3
do_test(TYPE3)
end
end

Otherwise, how about:

class TC_CreateOrder1 < TC_CreateOrder
FIXTURE = TYPE1
end

class TC_CreateOrder2 < TC_CreateOrder
FIXTURE = TYPE2
end

class TC_CreateOrder3 < TC_CreateOrder
FIXTURE = TYPE3
end

(I’m not sure how you’d prevent the base test TC_CreateOrder being run)

Regards,

Brian.


#4

On Fri, 30 Mar 2007, Matt B. wrote:

these as separate tests.

def setup
TEST_DATA = YAML.load(IO.read(ENV[‘TEST_DATA’])) # TEST_DATA is a
filename for
# yaml data
end

TEST_DATA=a.yml ruby test/a.rb

-a


#5

On Fri, Mar 30, 2007 at 12:41:54AM +0900, Matt B. wrote:

This would work ok if there was only one test method and only 3 types.
Now let’s say that I want to use this test technique multiple times,
with multiple test methods. And, the data input is over 100 items.
Duplicating this structure 100 times doesn’t seem tenable.

end
But this was just an example; if this works then you can do it
dynamically.

How about something like:

$test_classes = []

fixtures = [TYPE1, TYPE2, TYPE3]
fixtures.each do |f|
klass = Class.new(TC_CreateOrder)
klass.const_set(:FIXTURE, f)
$test_classes << klass # to prevent garbage collection
end


#6

You could write a private method in your test class which is called from
a
public test method which in turn gets the data from a YAML file or some
other data source.

e.g


require ‘test/unit’

class MyTest < Test::Unit::TestCase

def test_public
3.times { |i| _test_private(i) } # get your input data here before
calling private method
end

def _test_private(arg)
puts “Now testing with #{arg}”
assert(true)
end

private :_test_private
end


Loaded suite test
Started
Now testing with 0
Now testing with 1
Now testing with 2

  • nasir

#7

Thanks to everyone who posted responses. Through a combination of your
feedback and experimentation, here is the solution I came up with:

class TC_CreateOrder < Test::Unit::TestCase
def test_NewOrder
orderTypeList = File.open(‘orders.yaml’) { |yf| YAML::load(yf) }
orderTypeList.each { |type|
# perform the test
assert “order successful”
@_result.add_run
end
end

The trick was the last line “@_result.add_run”. By adding this line,
each time through the loop increments the test count such that each
order is a separate test case.

Nasir K. wrote:

You could write a private method in your test class which is called from
a
public test method which in turn gets the data from a YAML file or some
other data source.

e.g


require ‘test/unit’

class MyTest < Test::Unit::TestCase

def test_public
3.times { |i| _test_private(i) } # get your input data here before
calling private method
end

def _test_private(arg)
puts “Now testing with #{arg}”
assert(true)
end

private :_test_private
end


Loaded suite test
Started
Now testing with 0
Now testing with 1
Now testing with 2

  • nasir