Trouble with executing discrete testcase functions within a Test::Unit::TestCase class

Hi,

I was having some trouble trying to execute a set of testcase functions (to
run Selenium tests) within a class inherited from the Test::Unit::TestCase
class... the issue here is, I need access to individual functions within the
class, to be executed by a separate program that dynamically decides what
functions to be run.

The model I'm using is briefly detailed below...

a. A QtRuby application reads from the .rb file and parses for all 'def's
that exist within the file
b. Users can use the QtRuby app to create testcases (comprised of a
selection of the functions in the ruby file, with custom parameters entered
in the QtRuby app for each function)
c. These testcases can then be combined in the app to form suites that can
be executed.

When a suite is to be executed, I need access to the individual functions
within the Test::Unit::TestCase class. The way the test/unit library works -
executing all functions starting with 'test' - doesn't work well for me, as
I need to dynamically select the individual functions. The functionality
that allows suites to be created by combining all 'test' functions within
each class inherited from Test::Unit::TestCase is limiting because it
automatically executes ALL the functions within the class. I do not want to
create a separate class for each testcase, as I don't want to run 'setup'
and 'teardown' separately for each testcase, and there are dependencies
between the discrete functions in the one class that I'm using now.

One (ugly) solution that WILL work is dynamically creating a new .rb file to
execute selected tests - this .rb file will have a single
Test::Unit::TestCase class, and each test function will dynamically be
inserted into the class by copying it from the 'master' .rb file... but this
is ugly, as I'll have to parse through the entire ruby file containing the
actual testcase functions, looking for 'def's, if-blocks, class-blocks etc.,
counting the 'end's to be able to extract only the specific functions I
need. There has to be a better way, as this will depend too heavily on
parsing the Ruby language itself.

Can anyone please tell me a way in which I can do something like the
below...?

include 'master-file.rb'

a = TestSomething.new #TestSomething being the class inherited from
Test::Unit::TestCase, which also contains the testcase functions
result = a.function(parm1, parm2, ... , parm x) #'function' being any one of
the multiple functions within the class TestSomething that actually does any
testing

Lots of gratefulness will ensue :slight_smile:

···

--
"I refuse to prove that I exist," says God, "for proof denies faith, and
without faith I am nothing."
"But," says Man, "the Babel fish is a dead giveaway isn't it? It could not
have evolved by chance. It proves that you exist, and so therefore, by your
own arguments, you don't. Q.E.D."
"Oh dear," says God, "I hadn't thought of that," and promptly vanishes in a
puff of logic.
"Oh, that was easy," says Man, and for an encore goes on to prove that black
is white and gets himself killed on the next zebra crossing.

Kp schrieb:

(...)
The model I'm using is briefly detailed below...

a. A QtRuby application reads from the .rb file and parses for all 'def's
that exist within the file
b. Users can use the QtRuby app to create testcases (comprised of a
selection of the functions in the ruby file, with custom parameters entered
in the QtRuby app for each function)
c. These testcases can then be combined in the app to form suites that can
be executed.
(...)

I'm not sure I understand what you want. Since test methods have no parameters, they can't be the "functions" you are talking about. So, what are those functions doing? Who calls the actual test methods?

Regards,
Pit

Hi,

Yes, the 'functions' I'm talking about are not the functions that will
automatically be executed, and their names don't start with 'test...'.

But since they are within the Test::Unit:TestCase class, they have access to
methods such as 'assert' etc.

What I need is a way to access and run these functions from an external
program (a different .rb file). I don't want these functions to be run
automatically as unit-testing tests, as I'm using them to test functionality
of a web-based app using the Selenium-RC tool.

Hope I was clearer here... much thanks for your reply.

Kp.

···

On 1/10/07, Pit Capitain <pit@capitain.de> wrote:

Kp schrieb:
> (...)
> The model I'm using is briefly detailed below...
>
> a. A QtRuby application reads from the .rb file and parses for all
'def's
> that exist within the file
> b. Users can use the QtRuby app to create testcases (comprised of a
> selection of the functions in the ruby file, with custom parameters
entered
> in the QtRuby app for each function)
> c. These testcases can then be combined in the app to form suites that
can
> be executed.
> (...)

I'm not sure I understand what you want. Since test methods have no
parameters, they can't be the "functions" you are talking about. So,
what are those functions doing? Who calls the actual test methods?

Regards,
Pit

--
"I refuse to prove that I exist," says God, "for proof denies faith, and
without faith I am nothing."
"But," says Man, "the Babel fish is a dead giveaway isn't it? It could not
have evolved by chance. It proves that you exist, and so therefore, by your
own arguments, you don't. Q.E.D."
"Oh dear," says God, "I hadn't thought of that," and promptly vanishes in a
puff of logic.
"Oh, that was easy," says Man, and for an encore goes on to prove that black
is white and gets himself killed on the next zebra crossing.

Kp schrieb:

Yes, the 'functions' I'm talking about are not the functions that will
automatically be executed, and their names don't start with 'test...'.

But since they are within the Test::Unit:TestCase class, they have access to
methods such as 'assert' etc.

What I need is a way to access and run these functions from an external
program (a different .rb file). I don't want these functions to be run
automatically as unit-testing tests, as I'm using them to test functionality
of a web-based app using the Selenium-RC tool.

Hope I was clearer here... much thanks for your reply.

Kp, why do you put your methods in a subclass of Test::Unit::TestCase? If all you need are the assertion methods you can do something like this:

   require "test/unit/assertions"

   class C
     include Test::Unit::Assertions
     def check_successor a, b
       assert_equal a, b.succ
     end
   end

   c = C.new
   c.check_successor 2, 1
   c.check_successor 3, 1 rescue puts $!

   # => <3> expected but was
   # => <2>.

This way the automatic test runner of test/unit isn't run.

If you have problems calling those methods "from an external program", maybe you should look at the #send method. Continuing the code above:

   methods_to_run_with_args = [
     [ "check_successor", "b", "a" ],
     [ "check_successor", "c", "a" ],
     [ "check_successor", 3, 2 ],
     [ "check_successor", 4, 2 ],
   ]

   methods_to_run_with_args.each do |name, *args|
     begin
       print "running #{name} with #{args.inspect}: "
       c.send name, *args # <<< here is c.send
     rescue Test::Unit::AssertionFailedError
       puts "failed"
     rescue Exception
       puts "error"
     else
       puts "ok"
     end
   end

   # => running check_successor with ["b", "a"]: ok
   # => running check_successor with ["c", "a"]: failed
   # => running check_successor with [3, 2]: ok
   # => running check_successor with [4, 2]: failed

Sorry if I told you things you already know. Feel free to ask again if this doesn't answer your question.

Regards,
Pit

Hi,

No, you didn't tell me things I already know :slight_smile: Thanks a LOT for your
help...

I temporarily got around my troubles by creating a ruby file with the
functions I needed to be run, 'load'ed the file into the .rb file that
contains the Test::Unit::TestCase class, and ran it from there.

This worked for me, but your solution appears to be more elegant - I'll be
switching to the 'send' way of doing things.

Thanks again!

Kp.

···

On 1/11/07, Pit Capitain <pit@capitain.de> wrote:

Kp schrieb:
> Yes, the 'functions' I'm talking about are not the functions that will
> automatically be executed, and their names don't start with 'test...'.
>
> But since they are within the Test::Unit:TestCase class, they have
> access to
> methods such as 'assert' etc.
>
> What I need is a way to access and run these functions from an external
> program (a different .rb file). I don't want these functions to be run
> automatically as unit-testing tests, as I'm using them to test
> functionality
> of a web-based app using the Selenium-RC tool.
>
> Hope I was clearer here... much thanks for your reply.

Kp, why do you put your methods in a subclass of Test::Unit::TestCase?
If all you need are the assertion methods you can do something like this:

   require "test/unit/assertions"

   class C
     include Test::Unit::Assertions
     def check_successor a, b
       assert_equal a, b.succ
     end
   end

   c = C.new
   c.check_successor 2, 1
   c.check_successor 3, 1 rescue puts $!

   # => <3> expected but was
   # => <2>.

This way the automatic test runner of test/unit isn't run.

If you have problems calling those methods "from an external program",
maybe you should look at the #send method. Continuing the code above:

   methods_to_run_with_args = [
     [ "check_successor", "b", "a" ],
     [ "check_successor", "c", "a" ],
     [ "check_successor", 3, 2 ],
     [ "check_successor", 4, 2 ],
   ]

   methods_to_run_with_args.each do |name, *args|
     begin
       print "running #{name} with #{args.inspect}: "
       c.send name, *args # <<< here is c.send
     rescue Test::Unit::AssertionFailedError
       puts "failed"
     rescue Exception
       puts "error"
     else
       puts "ok"
     end
   end

   # => running check_successor with ["b", "a"]: ok
   # => running check_successor with ["c", "a"]: failed
   # => running check_successor with [3, 2]: ok
   # => running check_successor with [4, 2]: failed

Sorry if I told you things you already know. Feel free to ask again if
this doesn't answer your question.

Regards,
Pit

--
"I refuse to prove that I exist," says God, "for proof denies faith, and
without faith I am nothing."
"But," says Man, "the Babel fish is a dead giveaway isn't it? It could not
have evolved by chance. It proves that you exist, and so therefore, by your
own arguments, you don't. Q.E.D."
"Oh dear," says God, "I hadn't thought of that," and promptly vanishes in a
puff of logic.
"Oh, that was easy," says Man, and for an encore goes on to prove that black
is white and gets himself killed on the next zebra crossing.