Using Isolate.Invoke.Event enable event driven unit testing by invoking events on fake or “real” object. If you use events to communicate between parts of your application – it’s a feature you need to know and use. In the last couple of months I have been using it a lot but there is one wall I keep on hitting – when I use Isolate.Swap to fake an instance inside my production code it’s impossible to invoke events on it – because I cannot “touch” the actual faked instance – or is it?
But first things first – let’s talk about invoking events using Typemock Isolator…
Invoking events using Isolator
Let’s say I have a special kind of calculator that due strange consequences known only to the product manager need to work via events. The calculator shell “listen” for events from an “input provider”.
Presented with the code below – how can you test it?
One way to test the code is to use Isolate.Invoke (I bet you didn’t see this one coming):
For those of you that see event invocation for the first time it might be a little confusing. Isolator use a trick to record the event namely putting the event’s add handler call (the “+=”) inside a lambda. The other two parameters are the events parameters – “this” and “eventArgs”.
Invoking event is a simple as long as you can reach the instance that holds the event – which is not the case if you use Isolate.Swap
Invoking events on future instances
What happens if we need to invoke event on an instance that is created deep inside the production code? at work we use timers and need to test behavior dependent on timer elapsed event – just like in the next class:
It’s not the a very sophisticated class – but it was created to make a point, a timer is created and each time it invokes an event something happens – for simplicity sake I choose to increase a counter.
Testing it should be easy – we have Isolate.Swap and we know how to invoke events, so it shouldn’t be hard to come up with the following test:
The test above is simple, elegant and very wrong – it would fail each time you run it claiming that the counter is still ‘0’. So what went wrong? Swap doesn’t actually swap the next instance, it swap it’s behavior instead – meaning that when we call invoke on the fake object it doesn’t invoke event on the object inside our class. I know the good people of Typemock would add this cool feature someday but until then we have a problem – in order to invoke events we need to be able to “touch” the instance in the test.
The solution – reflection
Gur Kashi has come up with a simple solution to this issue – why not use reflection to get the field and use it to invoke the event – the cool thing about Isolator is that it can invoke events on “real” objects as well not just fakes.
With the aid of the following utility method – the class has become testable:
And now in the test we can drop the fake instance and just call invoke
That’s it. The only downside of this solution is that it’s string based and the test might break if the field name is changed – so make sure you have a good error message if the fields was not found.