Я Java-разработчик, играющий с Ruby, и мне он нравится. Я понял, что благодаря средствам метапрограммирования Ruby мои модульные тесты стали намного чище, и мне не нужны неприятные фреймворки для имитации. У меня есть класс, которому нужны службы класса File, и в моем тесте я не хочу трогать свою настоящую файловую систему. В Java я бы использовал некоторую виртуальную файловую систему для упрощения «швов» для передачи фальшивых объектов, но в Ruby это явно излишне. То, что я придумываю, кажется уже действительно приятным по сравнению с миром Java. В моем тестируемом классе у меня есть необязательный параметр конструктора:
def initialize(file_class=File)
Когда мне нужно открыть файлы в моем классе, я могу сделать это:
@file_class.open(filename)
И вызов идет либо к настоящему файловому классу, либо, в случае моего модульного теста, к поддельному классу, который не касается файловой системы. Я знаю, что должен быть лучший способ сделать это с помощью метапрограммирования?

Mocha (http://mocha.rubyforge.org/) - очень хорошая имитирующая библиотека для Ruby. В зависимости от того, что вы на самом деле хотите протестировать (например, если вы хотите просто подделать вызов File.new, чтобы избежать зависимости файловой системы, или если вы хотите убедиться, что правильные аргументы передаются в File.new), вы можете сделать что-то вроде этого:
require 'mocha'
mock_file_obj = mock("My Mock File") do
stubs(:some_instance_method).returns("foo")
end
File.stubs(:new).with(is_a(String)).returns(mock_file_obj)
Я не вижу необходимости испытывать отвращение к издевательской библиотеке. Mocha просто выполняет метапрограммирование за вас (т. Е. Методы переопределения и т. д.), О которых вы просите делать вручную.
@BrianPhillips Как вы проверяете, что заглушенные методы были вызваны
@AnkitDhingra Mocha поддерживает более детальные ожидания. если вы используете метод «ожидает» вместо «заглушек», то после запуска теста он выдаст ошибку, если фиктивный метод не был вызван.
В случае, который вы описали, я бы предположил, что то, что вы делаете, кажется нормальным. Я знаю, что эту технику пропагандировал Джеймс Мид (автор Mocha). Нет необходимости заниматься метапрограммированием только ради этого. Вот что Джеймс сказал об этом (и длинный список других техник, которые вы можете попробовать)
Для меня это особенно трудная задача. С помощью, которую я получил от этот вопрос, и некоторой дополнительной работы от моего имени, вот решение, к которому я пришел.
# lib/real_thing.rb
class RealThing
def initialize a, b, c
# ...
end
end
# test/test_real_thing.rb
class TestRealThing < MiniTest::Unit::TestCase
class Fake < RealThing; end
def test_real_thing_initializer
fake = mock()
Fake.expects(:new).with(1, 2, 3).returns(fake)
assert_equal fake, Fake.new(1, 2, 3)
end
end
Да, я бы вообще предпочел не использовать имитирующую библиотеку. Вы действительно нуждаетесь в них в Ruby?