Направляющие: Как делают меня тесты записи на рубиновый модуль?

Я хотел бы знать, как записать модульные тесты на модуль, который смешан в несколько классов, но не вполне знайте, как пойти об этом:

  1. Я тестирую методы экземпляра путем записи тестов в одном из тестовых файлов для класса, который включает их (не кажется правильным), или можно ли так или иначе сохранить тесты для включенных методов в отдельном файле характерными для модуля?

  2. Тот же вопрос относится к методам класса.

  3. У меня должен быть отдельный тестовый файл для каждого из классов в модуле как нормальные модели направляющих, делают, или они живут в общем тестовом файле модуля, если это существует?

47
задан tsdbrown 27 January 2010 в 10:27
поделиться

4 ответа

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

setup do
  @object = Object.new
  @object.extend(Greeter)
end

should "greet person" do
  @object.stubs(:format).returns("Hello {{NAME}}")
  assert_equal "Hello World", @object.greet("World")
end

should "greet person in pirate" do
  @object.stubs(:format).returns("Avast {{NAME}} lad!")
  assert_equal "Avast Jim lad!", @object.greet("Jim")
end

Если ваши модульные тесты являются хорошими, вы должны быть в состоянии просто проверить тест Функциональность в модулях она смешана.

ИЛИ ...

Написать тестовый помощник, который утверждает правильное поведение, затем используйте это против каждого класса, он смешан. Использование было бы следующим:

setup do
  @object = FooClass.new
end

should_act_as_greeter

Если ваши модульные тесты хороши, это может быть просто Проверка дыма ожидаемого поведения, проверка правых делегатов и т. Д.

57
ответ дан 26 November 2019 в 19:42
поделиться

Не используйте сообщение для поиска. Поиск может быть благополучно сделать с Get, поскольку он ничего не изменит.

-121--2195374-

Я, как правило, в целом проверил модуль как можно больше изоляции, по сути, проверяя методы, с достаточном кодом, издевателями и заглушками для его работы.

У меня, вероятно, также имели испытания на классы, в которые включены модули. Я не могу проверить каждый класс, но проведет достаточно классов, чтобы получить хорошее покрытие и иметь понимание любых проблем, которые возникают. Эти тесты не нужно явно проверить модуль, но, безусловно, будет тестировать его использование в частности сценарии.

Каждый набор испытаний будет иметь свой собственный файл.

3
ответ дан 26 November 2019 в 19:42
поделиться

Используйте встроенные классы (я не использую флексмак или stubba/mocha только для того, чтобы показать суть)

def test_should_callout_to_foo
   m = Class.new do
     include ModuleUnderTest
     def foo
        3
     end
   end.new
   assert_equal 6, m.foo_multiplied_by_two
 end

Любая издевательская библиотека/нарезка должна дать вам более чистый способ сделать это. Также вы можете использовать structs:

 instance = Struct.new(:foo).new
 class<<instance
     include ModuleUnderTest
 end
 instance.foo = 4

Если у меня есть модуль, который используется во многих местах, у меня есть юнит-тест для него, который делает именно это (сдвиньте тестовый объект под модульные методы и проверьте, корректно ли работают модульные методы на этом объекте).

13
ответ дан 26 November 2019 в 19:42
поделиться

Я пытаюсь сохранить свои тесты, сосредоточенные только на договоре к этому конкретному классу / модулю Отказ Если я доказал, что поведение модуля в классе тестирования для этого модуля (обычно, включая этот модуль в тестовом классе, объявленном в спецификации для этого модуля), то я не буду дублировать этот тест для класса производства, который использует этот модуль. Но если есть дополнительное поведение, которое я хочу проверить для класса производства, или проблемы интеграции, я напишу тесты для класса производства.

Например, у меня есть модуль под названием Attributevalidator , который выполняет легкие валидации в виде аналогичных ActiveRecord . Я пишу тесты для поведения модуля в спецификации модуля:

before(:each) do
  @attribute_validator = TestAttributeValidator.new
end

describe "after set callbacks" do
  it "should be invoked when an attribute is set" do
    def @attribute_validator.after_set_attribute_one; end
    @attribute_validator.should_receive(:after_set_attribute_one).once
    @attribute_validator.attribute_one = "asdf"
  end
end

class TestAttributeValidator 
    include AttributeValidator
    validating_str_accessor [:attribute_one, /\d{2,5}/]      
end

Теперь в классе производства, который включает в себя модуль, я не буду подтвердить, что обратные вызовы сделаны, но я могу утверждать, что включенный класс имеет определенную проверку Установите с определенным регулярным выражением, что-то особенное для этого класса, но не воспроизводя тесты, которые я написал для модуля. В спецификации для класса производства я хочу гарантировать, что конкретные валидации устанавливаются, но не при этом валидации работают в целом. Это своего рода тест интеграции, но тот, который не повторяет те же утверждения, которые я сделал для модуля:

describe "ProductionClass validation" do
  it "should return true if the attribute is valid" do
    @production_class.attribute = @valid_attribute 
    @production_class.is_valid?.should be_true
  end
  it "should return false if the attribute is invalid" do
    @production_class.attribute = @invalid_attribute
    @production_class.is valid?.should be_false
  end
end

здесь есть некоторая дублирование здесь (поскольку большинство интеграционных тестов будут иметь), но тесты доказывают две разные вещи для меня Отказ Один набор тестов доказывает общее поведение модуля, другой доказывает конкретные проблемы реализации производственного класса, который использует этот модуль. Из этих тестов я знаю, что модуль будет проверять атрибуты и выполнять обратные вызовы, и я знаю, что мой класс производства имеет определенный набор валидаций для конкретных критериев, уникальных для класса производства.

Надеюсь, что поможет.

4
ответ дан 26 November 2019 в 19:42
поделиться
Другие вопросы по тегам:

Похожие вопросы: