Ruby / Minitest Spec: Как проверить, что метод возвращает значение в данном массиве? - PullRequest
0 голосов
/ 26 мая 2019

У меня есть следующий класс:

  class State
    def self.alive
      :alive
    end

    def self.dead
      :dead
    end
  end

Тестирование простое:

it 'should report the expected state for alive' do
  State.alive.must_equal :alive
end

it 'should report the expected state for dead' do
  State.dead.must_equal :dead
end

Я хочу добавить метод класса, который возвращает случайное состояние.

class State
# ...
    def self.random
      [alive, dead].sample
    end

Однако я не уверен, какое утверждение мне нужно использовать.

В настоящее время я тестирую его следующим образом:

  it 'should return a random state' do
    %i[dead alive].must_include State.random
  end

Что сзади. Приведенный выше тест проверяет буквальный массив, а не класс State.

Есть ли лучший способ проверить, что метод возвращает значение, включенное в указанный массив?

1 Ответ

3 голосов
/ 26 мая 2019

Прежде чем предложить вам решение, я хочу раскрыть некоторые подробности о Spec DSL и Minitest. Методы must_include - это ожидание Spec DSL для утверждения assert_includes. Этот метод имеет следующую подпись:

assert_includes collection, obj, msg = nil

Когда создается ожидание, подпись:

Collection#must_include obj, msg = nil

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

module Minitest::Assertions
  ##
  # Fails unless +obj+ is included in +collection+.

  def assert_included_in obj, collection, msg = nil
    msg = message(msg) {
      "Expected #{mu_pp(obj)} to be included in #{mu_pp(collection)}"
    }
    assert_respond_to collection, :include?
    assert collection.include?(obj), msg
  end
end

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

module Minitest::Expectations
  ##
  # See Minitest::Assertions#assert_included_in
  #
  #    collection.must_be_one_of obj
  #
  # :method: must_be_one_of

  infect_an_assertion :assert_included_in, :must_be_one_of, :reverse
end

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

it "should return a random state" do
  State.random.must_be_one_of %i[dead alive]
end

Я бы сделал еще один шаг вперед и использовал бы монаду значений для вызова ожидания:

it "should return a random state" do
  value(State.random).must_be_one_of %i[dead alive]
end
...