Ruby测试期望运行一个命令



我用Minitest和Mocha测试我的Rails应用程序进行单元测试和集成测试,并想测试是否使用某些参数调用命令行命令。

比方说,我有一门课:

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

我的测试only想知道带有这些参数的命令是否运行。而不是它是否使用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")对内部工作假设太多,一旦我将其转移到例如resque,就会失败。

我的其他选择是什么?有没有一种方法可以在较低级别上模拟或存根并期望system?是否有一种模式或gem允许以更通用的方式模拟和期望命令?

有一条经验法则,您应该"只模拟您拥有的对象"。在这种情况下,您似乎希望确保创建了压缩的存档。您可能应该在应用程序中的某个位置有一个对象或方法,该对象或方法的唯一责任是执行此操作。

假设您有一个名为create_archive的方法来执行此操作。有了create_archive上适当的单元测试覆盖率,您可以简单地验证它是从集成测试中调用的。您应该期望并验证是否调用了此方法,而不是调用Kernel#systemKernel#`。这些调用是实现细节,您需要验证逻辑(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

您所做的是集成测试。您还需要一个低级别的单元测试,它不关心system方法的结果,但要确保它会被正确调用。

我只知道Rspec的方法,但不知道minitest,它使用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

最新更新