Search >>

RSS   COM     HOME

>    Unit Testing and Threads

Jul
19
06


While working on the IM application, a pattern seems to be emerging for the tests that I write. I have an object that is supposed to wait for something to happen, and when that something occurs that object is expected to notify another object by making a call to it. For instance, I have a class that waits for something to be sent over a socket, and signal a client when it has received what it needs. Waiting for something to happen on a socket means that the current thread cannot do anything else while waiting - that operation needs to be done on a worker thread.

When I write a test for that type of operation it follows a pattern similar to:

  1. Create a test double that we expect to be notified by the class under test.
  2. Call the CUT and pass it the test double
  3. The CUT starts a worker thread, which waits for the event to occur and calls back when it does
  4. The call to the CUT returns to the test code before the callback to the test double has been made
  5. The test code does whatever it needs to make the CUT notice that it needs to notify the test double
  6. The test code waits for the test double to be called
  7. The CUT makes the call to the test double that in turn signals to the test code that the operation has finished
  8. The test code makes whatever assertions it need to make sure that the test has passed

I ended up creating a class, SignallingWrapper that wraps all of this behavior. Using it for a test like the one above looks something like this


def test_with_threads
  testDouble = create_test_double

  wrapper = SignallingWrapper.new(testDouble, ["method_on_test_double"])
  wrapper.call_in_context do
    object_under_test.method_to_test(wrapper)
    wrapper.wait_for("method_on_test_double")
  end

  assert(testDouble.didItWork?)
end

In the code above we create a SignallingWrapper around the test double, passing along the name of the method that we expect the CUT to call back. We then call the CUT inside a test context, which makes sure that thread synchronization works properly. After that we wait for the method on the test double to be called properly. Finally, we assert whatever is necessary to complete the test.

You can specify, and wait for, more than one method on the test double.

The SignallingWrapper seems to do the trick for me. It may very well be the case that I really should refactor the tests so that threading is not an issue, but I don’t see a clean way to do that at the moment. In any way I had a blast implementing this. It introduced me to concepts like object-specific classes and dynamically defining methods. Ruby contains a lot of stuff. Perhaps too much…

You can take a look at SignallingWrapper here.






  One Response to “Unit Testing and Threads”



  1. Off Topic: This is just a quick note to invite you to register your blog at RubyCorner.com, a meeting place for people interested in the Ruby Programming Language or any of the related technologies.

>  Leave a Reply