Friday, January 13, 2012

Specs2 Mockito - Invoke Injected Callback

Mockito and Specs2 work great together and make testing my code a lot of fun. I ran into a problem yesterday in which I needed to get access to a callback function that was passed into an object that I was mocking. For some concreteness, I was mocking a zookeeper client and needed to invoke the callback function I passed to "zookeeper.watchNode(path, callbackFunction)".

Up until this point, I've only needed to verify arguments from my test. I haven't needed to actually do something with the argument itself. My original approach was to use a custom matcher to capture the parameter using function matchers. But that involved a var and was rather messy.

It turns out there is a MUCH better way to do this. Called "argument capture." In my case, my code looked like this:

      // The signature of the zookeeper watch function
      val listener = capture[(Option[Array[Byte]]) => Unit]

      // create system under test, which will call watchNode internally
      new SUT(zkMock)

      // Use the arg capturers to capture the params SUT passed in
      there was one(zkMock).watchNode(path, listener)

      // Now, call the callback method
      listener.value(Some("some updated value from zookeeper"))

      SUT.someValue must_== "some updated value"

1 comment:

  1. Typically you put the capture into the stubbing call, but like you show you can also do it in the verification (there was one...).