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

Dr1*_*1Ku 6 ruby testing amqp minitest eventmachine

我正在尝试整个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
Run Code Online (Sandbox Code Playgroud)

我已经注释掉了包含em-minitest-spec gem的功能,它应该强制规范在EventMachine反应堆内部运行,如果我包含它我会遇到一个甚至比较粗略的例外(我想)内联类等等:NoMethodError: undefined method 'include' for #<#<Class:0x3a1d480>:0x3b29e00>.

我正在测试的代码,即该connectService中的方法基于本文,如下所示:

# 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
Run Code Online (Sandbox Code Playgroud)

整个" 异常处理 "只是试图将异常冒泡到我可以捕获/处理它的地方,这也没有帮助,有或没有beginraise我在运行规范时仍然得到相同的结果:

EventMachine::ConnectionError: unable to resolve server address,这实际上是我所期望的,但却Minitest不能很好地适应整个反应堆的概念,并且未能在此基础上进行测试Exception.

那么问题仍然存在:一个测试EventMachine相关代码如何使用Minitest规范机制?另一个问题也一直在徘徊Cucumber,也没有答案.

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

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

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

提前致谢!

Ben*_*aum 5

很抱歉,如果这个回答过于迂腐,但是如果您区分单元测试和验收测试,我认为您可以更轻松地编写测试和库.

BDD与TDD

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

BDD

虽然我不确定你的服务应该做什么,但我想你的BDD测试看起来应该是这样的:

  1. 启动服务(如果需要,可以在测试中的单独线程中执行此操作)
  2. 写一些东西到队列
  3. 等待您的服务回复
  4. 检查服务的结果

换句话说,BDD(或验收测试,或集成测试,但您想要考虑它们)可以将您的应用程序视为应该提供某些功能(或行为)的黑盒子.测试让您专注于最终目标,但更多的是用于确保一两个黄金用例,而不是应用程序的稳健性.为此,您需要分解为单元测试.

TDD

在进行TDD时,让测试在一定程度上引导您进行代码组织.很难测试一个创建新线程的方法并在该线程中运行EM,但单独测试这些线程并不困难.因此,请考虑将主线程代码放入一个单独的函数中,您可以单独进行单元测试.然后,您可以在单元测试方法时将该方法存根connect.此外,不是测试当您尝试连接到错误的服务器(测试AMQP)时会发生什么,您可以测试当AMQP抛出错误(这是您的代码负责处理)时会发生什么.在这里,您的单元测试可以删除AMQP.connect抛出异常的响应.