Testing based on EventMachine (Reactor) Code

I tried the whole BDD approach and would like to test the AMQP -bounded aspect of the vanilla Ruby application that I am writing. Choosing Minitest as a test basis for the balance of functions and expressiveness, unlike other target vegetable frameworks, I decided to write this specification:

 # 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 

I commented on the inclusion of the em-minitest-spec gem function , which should force the specification to work inside the EventMachine reactor, if I turn it on, I encountered another exception due to (I suppose) built-in classes and such: NoMethodError: undefined method 'include' for #<#<Class:0x3a1d480>:0x3b29e00> .

The code I'm testing, namely the connect method in this service, is based on in this article and looks like this:

 # 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 

All exception handling is just an attempt to throw an exception from an exception in a place where I can catch / handle it, which also did not help, with or without the begin and raise bits, get the same result when spec starts:

EventMachine::ConnectionError: unable to resolve server address , which is actually what I would expect, but Minitest does not work very well with the concept of the entire reactor and does not pass the test based on this Exception .

The question remains: how to test EventMachine related code using Minitest spec-mechanisms? Another question also concerned Cucumber , also without an answer.

Or should I focus on my core functions (like messaging and viewing messages sent / received) and forget about edge cases? Any insight would really help!

Of course, everything can be reduced to what I wrote above, perhaps this is not the way to write / test these aspects. May be!

Notes on my environment: ruby 1.9.3p194 (2012-04-20) [i386-mingw32] (yes, Win32:>), minitest 3.2.0 , eventmachine (1.0.0.rc.4 x86-mingw32) , amqp (0.9.7)

Thanks in advance!

+6
source share
1 answer

Sorry if this answer is too pedantic, but I think it will be much easier for you to write tests and a library if you distinguish between your unit tests and your acceptance tests.

BDD vs TDD

Be careful not to confuse BDD with TDD. Although both of them are very useful, this can lead to problems when you try to test every edge case in the acceptance test. For example, BDD is testing what you are trying to do with your service, which is more about what you are doing with the message queue than connecting to the queue itself. What happens when you try to connect to a non-existent message queue, in my opinion, is more suitable for the unit test area. It is also worth noting that your service should not be responsible for testing the message queue itself, as this is AMQP's responsibility.

Bdd

While I'm not sure what your service should do for sure, I would suggest that your BDD tests should look something like this:

  • start the service (you can do this in a separate thread in the tests, if you need)
  • write something to the queue
  • wait for your service to respond.
  • check service results

In other words, BDD (or acceptance tests, or integration tests, however you want to think about them) can consider your application as a black box that should provide certain functionality (or behavior). Tests focus on the ultimate goal, but are more designed to provide one or two gold use cases, rather than application reliability. To do this, you need to break down the units.

TDD

When you do TDD, let the tests guide you a little in terms of code organization. It is difficult to test a method that creates a new thread and starts EM inside this thread, but it is not so difficult to unit test any of them separately. So, consider how to include the main stream code in a separate function that you can unit test separately. You can then drown out this method while unit testing the connect method. Also, instead of checking what happens when you try to connect to a bad server (which is testing AMQP), you can check what happens when AMQP gives an error message (which is responsible for your code). Here, your unit test can throw away the AMQP.connect answer to throw an exception.

+5
source

Source: https://habr.com/ru/post/919926/


All Articles