2010-04-01 1 views
2

У меня есть два модульных теста, которые должны делиться множеством обычных тестов с немного разными настройками. Если я напишу что-то вродеКак унаследовать абстрактные модульные тесты в Ruby?

class Abstract < Test::Unit::TestCase 
    def setup 
    @field = create 
    end 

    def test_1 
    ... 
    end 
end 

class Concrete1 < Abstract 
    def create 
    SomeClass1.new 
    end 
end 

class Concrete2 < Abstract 
    def create 
    SomeClass2.new 
    end 
end 

then Concrete1, похоже, не наследует тесты из Abstract. Или, по крайней мере, я не могу заставить их работать в затмении. Если я выберу «Запустить все тестовые таблицы» для файла, содержащего Concrete1, тогда выполняется Abstract, хотя я не хочу, чтобы это было. Если я укажу Concrete1, то он вообще не выполнит никаких тестов! Если я укажу test_1 в Concrete1, то он жалуется, что не может найти его («uncaught throw: invalid_test (ArgumentError)»).

Я новичок в Ruby. Что мне здесь не хватает?

ответ

7

Вопрос заключается в том, что, насколько я могу судить, Test::Unit отслеживает, какие классы наследуют от Test::Unit::TestCase, и, как следствие, будет только выполнения тестов из классов, которые непосредственно наследуют от него.

Способ работы с этим заключается в создании модуля с тестами, которые вы хотите, а затем включает этот модуль в классах, которые производятся от 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 

Выход:

 
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 
+0

Спасибо - это здорово! Это помогло мне, наконец, решить http://stackoverflow.com/questions/8888614/how-to-write-and-inherit-from-an-abstract-subclass-of-actioncontrollertestcase, который задан в контексте функциональности Rails (контроллер) тестов и, как таковая, имеет немного дополнительную проблему. –

+0

Еще одно замечание: к сожалению, похоже, что такой подход не позволяет переопределить включенные тесты. Я предполагаю, что для этого понадобится другой взлом :-( –

+0

Это не имеет смысла для меня. Если тестовые классы должны непосредственно наследоваться от Test :: Unit :: TestCase, то как ActiveSupport :: TestCase и ActionController :: TestCase не вызвать проблему, описанную в этом вопросе?Разве они оба не являются дополнительными уровнями наследования между Test :: Unit :: TestCase и конкретными классами? –

1

Проблема заключается в том, что Test::Unit::TestCase явно не запускать тесты, определенные в суперкласса по умолчанию. В частности, обратите внимание, что TestSuiteCreator не не запускать тесты, если Test::Unit::TestCase#valid? возвращает истинное (https://github.com/test-unit/test-unit/blob/2.5.5/lib/test/unit/testsuitecreator.rb#L40):

def append_test(suite, test_name) 
    test = @test_case.new(test_name) 
    yield(test) if block_given? 
    suite << test if test.valid? 
end 

А что определяет, является ли тест действителен? Тестовый пример действует по умолчанию, если этот класс явно определено, что метод, или если метод был определен в Module (https://github.com/test-unit/test-unit/blob/2.5.5/lib/test/unit/testcase.rb#L405-L418):

def valid? # :nodoc: 
    return false unless respond_to?(@method_name) 
    test_method = method(@method_name) 
    if @internal_data.have_test_data? 
    return false unless test_method.arity == 1 
    else 
    return false unless test_method.arity <= 0 
    end 
    owner = Util::MethodOwnerFinder.find(self, @method_name) 
    if owner.class != Module and self.class != owner 
    return false 
    end 
    true 
end 

Так в основном, если вы подкласс другого модульного тестирования класса, и вы хотите для запуска модульных тестов суперкласса, вы можете:

  • Пересмотрите те методы испытаний в подклассе и они называют метод тестирования вашего суперкласса
  • Переместить все ваши методы к модулю (как описано в другом ответе на эта резьба)
  • Переопределение метода valid? в подклассе, чтобы вернуть истинный:

def valid? return true end