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

发布于 2024-12-11 01:44:28 字数 704 浏览 0 评论 0原文

我对 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)>'

我希望此时连接被拒绝,但是我如何测试它而不是破坏测试?或者,我看到的输出是正确的吗?谢谢!

I'm extremely new to rspec, and I'm trying to write a test to ensure that an object that is created actually does exist. Here's what my test looks like now:

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

The problem is, I'm getting this output when I run the test:

  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)>'

I'm expecting the connection to be refused at this point, but how can I test for that instead of it breaking the test? Or, is what I'm seeing the correct output? Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

各空 2024-12-18 01:44:28

我认为这有两个问题。首先,您实际上正在尝试在测试中连接到外部服务。通常,您希望向被测对象提供某种代表您通常连接到的服务的模拟。根据您的问题和评论中的内容,我猜测您的代码需要进行以下更改才能正常工作:

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

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

第二件事是您使用 should_not raise_error 来忽略测试中的特定情况。可以将它与指定的错误一起使用,例如 should_not raise_error(ConnectionError),但是当您无法拯救自己时,抛出错误是正常的事情,并且您的测试将在不应该的情况下中断您稍后添加此行为。

该测试表明,您应该在调用 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

关于如何不最终陷入这种情况的一些想法;)像往常一样,测试中的问题通常是建筑问题的迹象。

I see two problems with this. First you are actually trying to connect to an external service in a test. Generally you want to feed the object under test some kind of mock that represents the service you normally connect to. I'm guessing by what you have in your question and in the comments that your code will need the following changes for that to work:

You need to build a facade, or proxy, object to "hide" the real service from your UserService object. That object should basically just map the underlying service one-to-one. The reason for this is that you don't want our internals tightly bound to an external service, you want them bound to your objects (and never tightly). The facade should not be unit tested, that would bring you right back to where you are now, and should not need to be unit tested since it doesn't contain any business logic.

The second thing is that you need dependency inversion to decouple your UserService object form a specific underlying service implementation. You want your UserServices constructor to take an object, any object, and call methods on that to do the service related stuff. Since your UserService no longer cares if it's a real service (and it shouldn't) or not you can feed it a simple stub during testing and not have to have your test break when an external service is slow or down or in any other way behaves unexpectedly.

The second thing is that you used should_not raise_error to ignore a specific case in your test. It's fine to use it with a specified error, like should_not raise_error(ConnectionError) but throwing errors is a normal thing to do when you can not rescue yourself and your test will then break when it shouldn't if you later add this behavior.

The test says that you should get a UserService object back when calling UserService.new(), it mentions nothing about not getting one back if ... What you should do to test properly in this case and to document the expected behavior is to feed it a working mock in the test you have now and create a second test like:

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

Just a few thoughts on how to not end up in this situation to begin with ;) As usual a problem in testing is usually a sign of a architectural problem.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文