Тестирование Ruby предполагает запуск команды

Я тестирую свое приложение Rails с помощью Minitest и Mocha для модульных и интеграционных тестов и хочу проверить, работает ли командная строка. команда вызывается с определенными параметрами.

Скажем, у меня есть класс:

class Provisioning::Backup
  def create(path)
    system("tar -czf #{path} bar.tar.gz")
  end
end

Мой тест только хочет знать, запускается ли эта команда с этими параметрами. И не использует ли он system() или его альтернативу ``. Или даже через resque и тд. Я хочу проверить снаружи, а не внутреннюю реализацию.

Поэтому я не доволен своим текущим решением в *test/integration/user_requests_backup_test.rb*:

class UserRequestsBackupTest < ActionDispatch::IntegrationTest
  test "requests for a backup runs a backup-script" do
    contact = contacts(:harry)
    site = contact.sites.first

    Provisioning::Backup.expects(:system).with("tar -xzf foo bar")

    post "/v1/sites/#{site.id}/backups"
    assert_response :success
  end

  # backup is already pending
  # backup fails
end

Это работает, но утверждает реализацию, а не поведение, потому что Provisioning::Backup.expects(:system).with("tar -xzf foo bar") слишком много предполагает о внутренней работе и потерпит неудачу, как только я перенесу это, например. спасать

Каковы мои другие варианты? Есть ли способ смоделировать или заглушить и ожидать system на более низком уровне? Может быть, есть шаблон или драгоценный камень, который позволяет издеваться и ожидать команд более общим способом?


person berkes    schedule 21.08.2013    source источник


Ответы (2)


существует эмпирическое правило, согласно которому вы должны «издеваться только над объектами, которыми владеете». В этом случае похоже, что вы хотите убедиться, что был создан сжатый архив. Вероятно, у вас должен быть объект или метод где-то в вашем приложении, единственной обязанностью которого является выполнение этого действия.

Предположим, у вас есть метод с именем create_archive, который делает это. При правильном покрытии модульным тестом create_archive вы можете просто убедиться, что он был вызван из вашего интеграционного теста. Вы должны ожидать и убедиться, что вызывается этот метод, а не вызов Kernel#system или Kernel#` . Эти вызовы являются деталями реализации, и вместо этого вы хотите проверить логику (create_archive).

class UserRequestsBackupTest < ActionDispatch::IntegrationTest
  test "requests for a backup runs a backup-script" do
    contact = contacts(:harry)
    site = contact.sites.first

    Provisioning::Backup.expects(:create_archive)

    post "/v1/sites/#{site.id}/backups"
    assert_response :success
  end
end
person blowmage    schedule 10.09.2013

То, что вы сделали, это интеграционный тест. Вам также нужен модульный тест низкого уровня, который не заботится о результате метода system, но убедитесь, что он будет вызываться правильно.

Я знаю только способ Rspec сделать это, но не минитест, который использует модуль rspec-mock.

describe Provisioning::Backup do
  subject { Provisioning::Backup.new }

  it "calls system method correctly" do
    subject.should_receive(:system).with('tar -czf #{path} bar.tar.gz')
    subject.create
  end
end
person Billy Chan    schedule 21.08.2013
comment
Да, у меня также есть юнит-тесты, которые проверяют методы и так далее. Мой вопрос заключается в том, что я хочу, чтобы мой интеграционный тест тестировал меньше реализации, потому что я тестирую эту реализацию в модульных тестах. Мой вопрос о том, как/не/тестировать реализацию в моем интеграционном тесте. - person berkes; 21.08.2013