Злоупотребляю ли я заглушкой в ​​своих модульных тестах?

Я разрабатываю приложение Ruby on Rails, и у меня есть модель BillingPlan, содержащая следующие методы:

class BillingPlan < ActiveRecord::Base
  # ...

  def billing_months
    dates = [Date.new(Date.today.year, start_month.value, billing_day)]

    while dates.size < billings_in_year
      dates << dates.last + recurrence.value.months
    end

    dates.map{ |d| d.month }
  end

  def billings_in_year
    12 / recurrence.value
  end
end

Чтобы протестировать код, я написал следующую спецификацию:

describe BillingPlan do
  # ...

  describe '#billings_in_year' do
    subject do
      (plan = BillingPlan.new).stubs(
        recurrence: stub(value: 4)
      ) && plan
    end

    it 'returns the number of billings in a year' do
      expect(subject.billings_in_year).to eq(3)
    end
  end

  describe '#billing_months' do
    subject do
      (plan = BillingPlan.new).stubs(
        recurrence: stub(value: 2),
        start_month: stub(value: 2),
        billings_in_year: 6,
        billing_day: 21
      ) && plan
    end

    it 'returns the months when billing is done' do
      expect(subject.billing_months).to eq([2, 4, 6, 8, 10, 12])
    end
  end
end

Как видите, мне удалось полностью изолировать два метода с помощью Mocha. Однако мне интересно, не злоупотребляю ли я заглушками в своем тесте? Не слишком ли это зависит от внутренней работы методов? Можете ли вы указать общее правило, чтобы узнать, насколько широко следует полагаться на насмешки/фальсификацию?

Примечание. recurrence и start_month являются объектами стороннего класса.


person Alessandro Desantis    schedule 27.02.2014    source источник


Ответы (1)


Ваши тесты заглушают то, что им нужно, чтобы изолировать тестируемые случаи, но они намекают на проблему ваших методов — они не подчиняются Закон Деметры:

  • Вы можете играть сами с собой.
  • Вы можете играть со своими игрушками (но их нельзя разбирать),
  • Вы можете играть с игрушками, которые вам подарили.
  • И вы можете играть с игрушками, которые вы сделали сами.

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

Предполагая, что это программа на Rails, очень легко изменить код, чтобы удовлетворить закону. Во-первых, мы делаем однострочное дополнение к классу User:

class User
  delegate :name, :to => :department, :prefix => true, :allow_nil => true
  # ...
end

Если это решение по какой-то причине не является жизнеспособным, вы можете использовать это решение:

Деметра не мешает нам взаимодействовать с объектами ассоциаций второго и третьего порядка; он просто утверждает, что мы не можем взаимодействовать со всеми этими объектами одним и тем же методом. Посмотрите еще раз на формулировку закона:

…все объекты, которым M отправляет сообщение…

Деметра — это правило только о методах; он не ограничивает набор типов, с которыми может взаимодействовать класс.

Так что это совершенно законно:

class StatPresenter
  def human_stats(human)
    "Age: #{human.age}.nCountry stats:n#{country_stats(human.country)}"
  end

  def country_stats(country)
    "  Mortality rate: #{country.mortality_rate}"
  end
end
person Uri Agassi    schedule 27.02.2014
comment
В этом конкретном случае я смог использовать recurrence_value и start_month_value, псевдонимы, добавленные автоматически. Большое спасибо, что напомнили мне о Законе Деметры: я помню, как читал об этом некоторое время назад, но никогда не следовал ему до сих пор. - person Alessandro Desantis; 28.02.2014