让rSpec检查是否能够创建对象?

时间:2011-10-19 21:51:07

标签: ruby-on-rails rspec rspec2 rspec-rails

我对rspec非常陌生,我正在尝试编写测试以确保创建的对象确实存在。这是我的测试现在的样子:

require 'spec_helper'

describe "UserService" do
  describe ".new" do
    it "should create a UserService object" do
      service = UserService.new
      service.should_not be_nil
    end
  end
end

问题是,我在运行测试时得到了这个输出:

  1) UserService.new should create a UserService object
     Failure/Error: service = UserService.new
     Errno::ECONNREFUSED:
       Connection refused - connect(2)
     # ./spec/requests/user_service_spec.rb:6:in `new'
     # ./spec/requests/user_service_spec.rb:6:in `block (3 levels) in <top (required)>'

我希望此时连接被拒绝,但我怎样才能测试它而不是打破测试呢?或者,我正在看到正确的输出?谢谢!

1 个答案:

答案 0 :(得分:1)

我发现这有两个问题。首先,您实际上是在尝试连接到测试中的外部服务。通常,您希望为测试对象提供某种代表您通常连接到的服务的模拟。我猜你的问题以及评论中你的代码需要进行以下更改才能实现:

您需要构建一个Facade或代理对象,以“隐藏”UserService对象中的实际服务。该对象基本上应该只是一对一地映射底层服务。这样做的原因是你不希望我们的内部紧密绑定到外部服务,你希望它们绑定到你的对象(并且永远不会紧密)。外观不应该经过单元测试,这样可以将您带回到现在的位置,并且不需要进行单元测试,因为它不包含任何业务逻辑。

第二件事是您需要依赖性反转来将您的UserService对象从特定的底层服务实现中分离出来。您希望UserServices构造函数获取对象,任何对象,并在其上调用方法来执行与服务相关的操作。由于您的UserService不再关心它是否是真实的服务(并且它不应该),您可以在测试期间将其提供给一个简单的存根,而不必在外部服务缓慢或关闭时或以任何其他方式让您的测试中断表现出乎意料。

第二件事是您使用should_not raise_error忽略测试中的特定案例。可以将它与指定的错误一起使用,例如should_not raise_error(ConnectionError)但是当你无法自救时,抛出错误是正常的事情,如果你以后添加这种行为,那么你的测试就会破坏。 / p>

测试说你应该在调用UserService.new()时得到一个UserService对象,如果......在这种情况下应该做些什么来正确测试并记录预期的行为是在你现在的测试中为它提供一个工作模拟,并创建第二个测试,如:

describe ".new" do
  it "when service is down should throw error" do
    UserService.new(offline_mock).should raise_error(ConnectionError)
  end
end

关于如何不在这种情况下开始的一些想法;)像往常一样,测试中的问题通常是架构问题的标志。