我用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#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
您所做的是集成测试。您还需要一个低级别的单元测试,它不关心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