FlexMock and RubyCocoa

Because FlexMock and RubyCocoa disagree about the use of method_missing, you need to use flexmock as follows:

flexmock(SomeSubclassOfNSObject)

If the method you want to mock isn’t already defined on SomeSubclassOfNSObject, you have to define it before mocking it:

class Watcher <  OSX::NSObject
  def observeValueForKeyPath_ofObject_change_context(
             keyPath, object, change, context)
  end
end

That is ugly and horrible, so I wrote some code to make the class for me. It’s called rubycocoa_flexmock. It’s used like the following. (I use Shoulda, plus I add some syntactic sugar of my own to FlexMock).

  CALLBACK=:observeValueForKeyPath_ofObject_change_context

  context change callbacks do
    setup do
      @watcher = rubycocoa_flexmock(CALLBACK, 4)       # DEFINITION
      @observed = ObservableValueHolder2.alloc.initWithValue(’original‘)
    end

    should include the keypath and changed object do
      add_observer(:watcher => @watcher, :forKeyPath => value‘)   

      during {
        @observed.value = hello
      }.behold! {
        @watcher.should_receive(CALLBACK).once.    # USE
                 with(’value‘, @observed, any, any)
      }

    end
  end

rubycocoa_flexmock can take multiple name/argcount pairs. It’s annoying that you have to give it that information. The problem is that the dependence on an existing method happens within should_receive, but the number of arguments is only known in the following with message. And if you never give it a with, the number of arguments is never known. RubyCocoa is picky about Ruby argument declarations matching exactly what it knows from Objective-C, and I haven’t found a way around that.

The declaration of rubycocoa_flexmock is here. Not the greatest code I’ve ever written, but ’twill serve, ’twill serve.

2 Responses to “FlexMock and RubyCocoa”

  1. Tom Macklin Says:

    Did you try any of the other Ruby tools for mocking? If so, were any others more effective?

  2. Brian Marick Says:

    I haven’t.

Leave a Reply

You must be logged in to post a comment.