Ты рядом.Вот как смоделировать этот вызов Person.new:
Сначала давайте сделаем классы Person
и Product
немного более реалистичными ...
class Person
def default_number_of_products
Product.new.default_number
end
end
class Product
attr_reader :default_number
def initialize
@default_number = 3
end
end
Теперь для Person
тестов, которые высмеивают класс Product
...
describe Person do
subject(:person) { described_class.new }
describe '#default_number_of_products' do
let(:product) { instance_double(Product, default_number: 42) }
before do
allow(Product).to receive(:new).and_return(product)
end
it 'returns 42' do
expect(person.default_number_of_products).to eq(42)
end
end
end
Если бы код в Product
был выполнен, вызов person.default_number_of_products
возвратил бы 3
.Вместо этого этот тест шпионил за Product.new
и возвращал двойное вместо реального Product
.Итак, когда код в person.default_number_of_products
выполняется, он видит двойное число, которое имеет default_number
, равное 42.
Наконец, в своем вопросе выше вы упомянули, что думали, что mocks должны позволить вам создать одинКласс без необходимости создавать коллаборационистов.Это верное утверждение.Однако в приведенных выше тестах instance_double(Product, ...)
фактически создает тип утки из реального класса Product
.Таким образом, это должно быть определено.Если вы хотите использовать TDD до создания класса Product
, вы можете передать строку вместо имени класса, например:
let(:product) { instance_double('product', default_number: 42) }
HTH