Abstract Tests vs AutoRunner

Rubies:

I'm trying to get some elaborate test suites working via the hidden call to
AutoRunner.

Because I can't declare which suites to run, the system tests anything that
derives from TestCase.

I want to do this:

class AbstractSuite < Test::Unit::TestCase
    def test_foo()
        p derive()
    end
end

class ConcreteSuiteA < AbstractSuite
    def derive()
        return 'like this'
    end
end

class ConcreteSuiteB < AbstractSuite
    def derive()
        return 'like that'
    end
end

That's the skeleton of the Abstract Test pattern, which is a major Good
Thing. It prevents us from writing zillions of duplicate test cases with
minimal differences between each one. For example, my derive() could return
an object that must pass the same tests as another object, obeying Liskov
Substitution Principle.

However, I can't do it like that, because AutoRunner hoovers up every class
derived from TestCase, and runs all of them as suites. I predictably get
"test_foo(AbstractSuite): NoMethodError: undefined method `derive'"

The ugly fix is this:

class ConcreteSuiteA < Test::Unit::TestCase
    def test_foo()
        p derive()
    end

    def derive()
        return 'like this'
    end
end

class ConcreteSuiteB < ConcreteSuiteA
    def derive()
        return 'like that'
    end
end

That works, but it's "not OO". ConcreteSuiteB is not truly a derived version
of ConcreteSuiteA.

So I'm asking this question because I don't understand mixins, or
AutoRunner, enough to fix this.

Could a mixin grant test cases to two concrete classes? Alternately, does
AutoRunner have a feature to bump a suite from its list?

···

--
  Phlip
  http://c2.com/cgi/wiki?ZeekLand <-- NOT a blog!!!

Indirectly answering your question, you could just define an empty
derive method in your AbstractSuite.

class AbstractSuite < Test::Unit::TestCase
   def test_foo()
       p derive()
   end
   def derive; end
end

Everything else remains the same, although the output from auto runner
will be a bit screwy (3 tests in this case, rather than the expected
2).

Chris

···

On 9/7/06, Phlip <phlipcpp@yahoo.com> wrote:

Rubies:

I'm trying to get some elaborate test suites working via the hidden call to
AutoRunner.

Because I can't declare which suites to run, the system tests anything that
derives from TestCase.

I want to do this:

class AbstractSuite < Test::Unit::TestCase
    def test_foo()
        p derive()
    end
end

class ConcreteSuiteA < AbstractSuite
    def derive()
        return 'like this'
    end
end

class ConcreteSuiteB < AbstractSuite
    def derive()
        return 'like that'
    end
end

That's the skeleton of the Abstract Test pattern, which is a major Good
Thing. It prevents us from writing zillions of duplicate test cases with
minimal differences between each one. For example, my derive() could return
an object that must pass the same tests as another object, obeying Liskov
Substitution Principle.

However, I can't do it like that, because AutoRunner hoovers up every class
derived from TestCase, and runs all of them as suites. I predictably get
"test_foo(AbstractSuite): NoMethodError: undefined method `derive'"

The ugly fix is this:

class ConcreteSuiteA < Test::Unit::TestCase
    def test_foo()
        p derive()
    end

    def derive()
        return 'like this'
    end
end

class ConcreteSuiteB < ConcreteSuiteA
    def derive()
        return 'like that'
    end
end

That works, but it's "not OO". ConcreteSuiteB is not truly a derived version
of ConcreteSuiteA.

So I'm asking this question because I don't understand mixins, or
AutoRunner, enough to fix this.

Could a mixin grant test cases to two concrete classes? Alternately, does
AutoRunner have a feature to bump a suite from its list?

--
  Phlip
  http://c2.com/cgi/wiki?ZeekLand <-- NOT a blog!!!

Once TestCase is a class you cannot mix it in easily (or at least I
think so). The reverse appproach would be much easier (to mix in your
common behaviour)

AutoRunner has command line parameter -t that allows to exclude test
case classes by a regex (-v /Abstract/). Another possibility is to
extend AutoRunner to not load a TestClass that has any subclasses.

class Class
  def has_subclasses?
      ObjectSpace.each_object(Class) { |c| return true if self > c }
  end
end

Look for @filters in the AutoRunner code. You could copy the behaviour
in -n and -t to add another parameter (e.g. --leaves-only) that will
add to @filters << Proc {|t| t (attached patch will do that)

Maybe you can even force the -t parameter

autorunner.patch (817 Bytes)

···

On 9/7/06, Phlip <phlipcpp@yahoo.com> wrote:

Could a mixin grant test cases to two concrete classes? Alternately, does
AutoRunner have a feature to bump a suite from its list?

"Phlip" <phlipcpp@yahoo.com> writes:

Could a mixin grant test cases to two concrete classes? Alternately,
does AutoRunner have a feature to bump a suite from its list?

Indeed it can:

  require 'test/unit'
  
  module AbstractSuite
    def test_foo()
      p derive()
    end
  end
  
  class ConcreteSuiteA < Test::Unit::TestCase
    include AbstractSuite
  
    def derive()
      return 'like this'
    end
  end
  
  class ConcreteSuiteB < Test::Unit::TestCase
    include AbstractSuite
  
    def derive()
      return 'like that'
    end
  end
  # >> Loaded suite -
  # >> Started
  # >> "like this"
  # >> ."like that"
  # >> .
  # >> Finished in 0.000816 seconds.
  # >>
  # >> 2 tests, 0 assertions, 0 failures, 0 errors

If you define your shared tests in a module, you can then 'include' it
in any number of suites derived from Test::Unit::TestCase.

-Marshall

Rubies:

I resemble that remark!

Could a mixin grant test cases to two concrete classes?

  require 'test/unit'

  module AbstractSuite
    def test_foo
      p derive
    end
  end

  class ConcreteSuiteA < Test::Unit::TestCase
    include AbstractSuite
    def derive
      return 'like this'
    end
  end

  class ConcreteSuiteB < Test::Unit::TestCase
    include AbstractSuite
    def derive
      return 'like that'
    end
  end

Outputs:

  Loaded suite t
  Started
  "like this"
  ."like that"
  .
  Finished in 0.000483 seconds.

  2 tests, 0 assertions, 0 failures, 0 errors

Which I think is what you're looking for.

HTH,

···

On 9/6/06, Phlip <phlipcpp@yahoo.com> wrote:

--
Nathaniel Talbott

<:((><

Chris Roos wrote:

class AbstractSuite < Test::Unit::TestCase
  def test_foo()
      p derive()
  end
  def derive; end
end

That would run test_foo() with a stub. Because the real derive() is
naturally important, this wouldn't work. It's also "not-OO", because it
isn't minimal!

I could do it like that if I were building the suites from scratch, and then
stubs would gracefully do nothing. But...

Nathaniel Talbott wrote:

class ConcreteSuiteA < Test::Unit::TestCase
   include AbstractSuite

Jeeze Louise, could this friggin' language ever make anything HARD?! I need
to log hours doing SOMETHING!!!

···

--
  Phlip
  http://www.greencheese.us/ZeekLand <-- NOT a blog!!!