How to Inherit Abstract Unit Tests in Ruby

How do I inherit abstract unit tests in Ruby?

The issue is that, as far as I can tell, Test::Unit keeps track of which classes inherit from Test::Unit::TestCase, and as a result, will only run tests from classes that directly inherit from it.

The way to work around this is to create a module with the tests you want, and then include that module in the classes that derive from Test::Unit::TestCase.

require 'test/unit'

module TestsToInclude
def test_name
assert(self.class.name.start_with?("Concrete"))
end
end

class Concrete1 < Test::Unit::TestCase
include TestsToInclude

def test_something_bad
assert(false)
end
end

class Concrete2 < Test::Unit::TestCase
include TestsToInclude

def test_something_good
assert(true)
end
end

Output:


Loaded suite a
Started
.F..
Finished in 0.027873 seconds.

1) Failure:
test_something_bad(Concrete1) [a.rb:13]:
<false> is not true.

4 tests, 4 assertions, 1 failures, 0 errors

shell returned 1

how to write and inherit from an abstract subclass of ActionController::TestCase

I finally figured this out - once I realised that this is a general Ruby Test::Unit issue rather a Rails testing issue, a quick google instantly revealed How do I inherit abstract unit tests in Ruby? which already had a good answer. Then the only missing piece was being able to use the syntactic sugar:

test "something should behave in a certain way" do
...
end

rather than

def test_something_should_behave_in_a_certain_way" do
...
end

I found the answer to this within the ActiveSupport codebase itself, under lib/active_support/test_case.rb:

extend ActiveSupport::Testing::Declarative

This module defines test as a class method (which is why extend is required rather than include).

So the complete solution looks like this:

# tests/functional/admin/availabilities_controller_test.rb

class Admin::AvailabilitiesControllerTest < ActionController::TestCase
tests Admin::AvailabilitiesController
include Admin::ControllerTests

# non-reusable tests and helper methods specific to this
# controller test go here
end

# lib/admin/controller_tests.rb

module Admin::ControllerTests
extend ActiveSupport::Testing::Declarative

test "this test can be reused by anything which includes this module" do
...
end
end

The downside of this module-based approach is that you can't override the included tests. I guess that's just a fundamental limitation of Test::Unit - maybe the best answer is to move to RSpec, but I don't know it well enough yet to be sure.

Testing abstract classes in Rspec

One possibility is to use anonymous classes.

  let(:fooMyClass) do
Class.new(MyClass) do
# ...
end
end

This way there is no need to do clean up.

Rails: Abstract Classes to apply to models

No, rails generators don't have this functionality, but you always can do it by yourself.

# app/models/creature.rb
class Creature
attr_accessor :eyes, :nose
end

# app/models/human.rb
class Human < Creature
end

# app/models/dog.rb
class Dog < Creature
end

Using strategy pattern in ruby unit testing

What I would do is create a base module with all the tests you want to run, and then initialize the objects in your derived classes. Something like this (using Ruby's built-in Test::Unit library):

module Testers
def test_something
assert_equal "expected result", @myobject.function_call
end

# ....
end

Then later on your actual test classes:

require 'test/unit'

class TestA < Test::Unit::TestCase
def setup
@myobject = A.new
end

include Testers
end

class TestB < Test::Unit::TestCase
def setup
@myobject = B.new
end

include Testers
end

The magic here is that using a mixin (combination of a module and include) you can have some of the nice aspects of multiple inheritance without actually having multiple inheritance.

c# How To test Inheritance of an Abstract class with protected methods with xunit

Using polymorphism, you will for sure be able to do as follows:

public class ClassB {
protected MethodB() {
}
}

public class ClassA : ClassB {
}

[TestFixture()]
public class TestA {
[Test()]
public void IsInstanceOfB() {
ClassA a = new ClassA();
Assert.IsInstanceOf(typeof(ClassB), a);
}
}

That is using NUnit, I guess there might be a similar approach with xUnit.

Ruby on Rails Single Table Inheritance (STI) and unit test problem (with PostgreSQL)

Turns out that the problem was due to the presence of:

./test/fixtures/technicians.yml
./test/fixtures/users.yml

This makes sense as the framework expected to be able to insert data into similarly named tables.

How do I run a Test::Unit suite to completion with a tally of tests/failures?

Some more background would be helpful. I can't say I understand the behavior you're seeing.

I'm using both the core test/unit lib that comes with ruby 1.8, as well as several versions of the gem with ruby 1.9. The normal behavior for both of these is to run the entire loaded suite to completion and summarize the results.

Running a script that says require 'test/unit' will add an on-exit hook to run Test::Unit::AutoRunner with a Test::Unit::Collector::ObjectSpace collector (i.e. runs every instance of Test::Unit::TestCase currently loaded in the global object space).

It's also fairly easy to write your own custom test runner which manually loads your test classes and packs them into a Test::Unit::TestSuite, and capture its results.

But with every version of test/unit I've used, I've always seen the entire suite finish and report both failures and errors. In lieu of further info, I'd suggest experimenting with a single dummy test so see how you should expect test/unit to behave.

For example

require 'test/unit'
class Foo < Test::Unit::TestCase
def testFoo
flunk 'bad foo'
end
end
class Bar < Test::Unit::TestCase
def testBar
raise 'bar bar'
end
end

gives

Loaded suite foo
Started EF Finished in 0.001000 seconds.

1) Error:
testBar(Bar)
RuntimeError: bad bar
foo.rb:9:in `testBar`

2) Failure:
testFoo(Foo) [foo.rb:4]:
bad foo

2 tests, 1 assertions, 1 failures, 1 errors, 0 skips

Lastly: where are you trying to rescue/ensure? In the test methods? Under normal circumstances, there's no reason to catch an AssertionFailedError. This is for Test::Unit::TestCase to do, as a way to count failures and give you the report you want. Catching this interferes with what test/unit is written to do.

unit-testing abstract classes and protected methods inside them

In order for you to test your abstract class you need to instantiate it. So create a class for testing purposes that inherits from your Component (abstract) class.

Aside from the interfaces being used I don't see much to Mock.



Related Topics



Leave a reply



Submit