ruby - 规范测试基于 EventMachine 的(Reactor)代码

标签 ruby testing amqp eventmachine minitest

我正在尝试整个 BDD方法并想测试 AMQP基于 Vanilla 的方面Ruby我正在写的应用程序。选择Minitest后作为与其他名副其实的蔬菜框架不同的平衡功能和表现力的测试框架,我着手编写此规范:

# File ./test/specs/services/my_service_spec.rb

# Requirements for test running and configuration
require "minitest/autorun"
require "./test/specs/spec_helper"

# External requires
# Minitest Specs for EventMachine
require "em/minitest/spec"

# Internal requirements
require "./services/distribution/my_service"

# Spec start
describe "MyService", "A Gateway to an AMQP Server" do

  # Connectivity
  it "cannot connect to an unreachable AMQP Server" do

   # This line breaks execution, commented out
   # include EM::MiniTest::Spec

   # ...
   # (abridged) Alter the configuration by specifying
   # an invalid host such as "l0c@alho$t" or such
   # ...

   # Try to connect and expect to fail with an Exception
   MyApp::MyService.connect.must_raise EventMachine::ConnectionError
  end

end

我已经注释掉了 the em-minitest-spec gem 的内容应该强制规范在 EventMachine 中运行的功能reactor,如果我包含它,我会遇到一个关于(我想)内联类等更粗略的异常:NoMethodError: undefined method 'include' for #<#<Class:0x3a1d480>:0x3b29e00> .

我正在测试的代码,即 connect该服务中的方法基于 on this article看起来像这样:

# Main namespace
module MyApp

  # Gateway to an AMQP Server
  class MyService

    # External requires
    require "eventmachine"
    require "amqp"

    # Main entry method, connects to the AMQP Server
    def self.connect

      # Add debugging, spawn a thread
      Thread.abort_on_exception = true
      begin
        @em_thread = Thread.new {
          begin
            EM.run do
              @connection  = AMQP.connect(@settings["amqp-server"])
              AMQP.channel = AMQP::Channel.new(@connection)
            end
          rescue
            raise
          end
        }

        # Fire up the thread
        @em_thread.join

        rescue Exception
          raise
        end
      end # method connect
  end
end  # class MyService

整个“异常处理”只是试图将异常冒泡到一个我可以捕获/处理它的地方,无论有没有begin,这都没有帮助。和 raise运行规范时我仍然得到相同的结果:

EventMachine::ConnectionError: unable to resolve server address ,这实际上是我所期望的,然而Minitest不能很好地适应整个 react 堆概念,并且未能通过此 Exception 的地面测试.

然后问题仍然存在:如何测试 EventMachine -相关代码使用Minitest的规范机制? Another question也一直在徘徊Cucumber , 也没有回答。

或者我应该专注于我的主要功能(例如消息传递和查看消息是否被发送/接收)而忘记边缘情况?任何见解都会真正有所帮助!

当然,这都可以归结为我上面写的代码,也许这不是编写/测试这些方面的方式。可能是!

关于我的环境的注释:ruby 1.9.3p194 (2012-04-20) [i386-mingw32] (是的,Win32 :>),minitest 3.2.0 , eventmachine (1.0.0.rc.4 x86-mingw32) , amqp (0.9.7)

提前致谢!

最佳答案

很抱歉,如果此回复过于迂腐,但我认为如果您区分单元测试和验收测试,您将更容易编写测试和库。

BDD 与 TDD

注意不要将 BDD 与 TDD 混淆。虽然两者都非常有用,但当您尝试在验收测试中测试每个边缘情况时,它可能会导致问题。例如,BDD 是关于测试您试图通过您的服务完成什么,这更多地与您对消息队列所做的事情有关,而不是连接到队列本身。在我看来,当您尝试连接到一个不存在的消息队列时会发生什么更适合单元测试的领域。还值得指出的是,您的服务不应该负责测试消息队列本身,因为这是 AMQP 的职责。

业务发展

虽然我不确定您的服务应该做什么,但我想您的 BDD 测试应该类似于:

  1. 启动服务(如果需要,可以在测试中的单独线程中执行此操作)
  2. 往队列里写点东西
  3. 等待您的服务响应
  4. 查看服务结果

换句话说,BDD(或验收测试或集成测试,无论您如何看待它们)可以将您的应用视为一个应该提供特定功能(或行为)的黑盒子。这些测试让您专注于您的最终目标,但更多的是为了确保一两个黄金用例,而不是应用程序的健壮性。为此,您需要分解为单元测试。

测试驱动

当您进行 TDD 时,让测试在代码组织方面为您提供一些指导。很难测试创建新线程并在该线程内运行 EM 的方法,但单独对其中任何一个进行单元测试并不难。因此,考虑将主线程代码放入一个单独的函数中,您可以单独对其进行单元测试。然后,您可以在对 connect 方法进行单元测试时删除该方法。此外,您可以测试当 AMQP 抛出错误时发生的情况(这是您的代码要处理的错误),而不是测试当您尝试连接到错误的服务器时会发生什么(这会测试 AMQP)。在这里,您的单元测试可以将 AMQP.connect 的响应 stub 以抛出异常。

关于ruby - 规范测试基于 EventMachine 的(Reactor)代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11374425/

相关文章:

java - 单元测试异步代码和没有外部可见效果的代码

java - 用 Mockito 验证一个函数被调用的次数有什么意义?

python - Django Celery 任务没有完成并且一直处于待处理状态

c++ - 如何使用依赖于另一个静态库的静态库进行编译

ruby - 如何将 UCS2 字符串转换为 UTF8?

ruby-on-rails - Ruby on Rails 脚本控制台

ruby - Chef : Can a variable set within one ruby_block be used later in a recipe?

python - 使用 Django/Python 获得最大测试覆盖率的最佳实践?

java - Spring 集成 - 队列/轮询器似乎在没有任何操作的情况下耗尽线程池

ruby - 在多线程环境中跨不同请求共享( Mechanize ) session ?