unit testing event handlers

I would like to unit test my event handlers (not integration test),
but I don't see a clear path.

If I could get a reference to the handler under test then I could mock
or stub anything I needed to prior to calling execute, but I don't see
a built in way of doing this.

I could createObject them in the test, but then I'd lose the goodies
provided with baseMXUnitTest.

So it looks to me like the only way would be to write a separate
coldbox.xml that loaded an IOC container full of mocks. And I'd really
rather not have 2 more configuration files to maintain.

Does anyone know of a way to do this? Or are people just running
integration tests on event handlers and calling it a day?

Hi Jon,

As of now, the way unit testing for handlers was designed, was to use them as a top-down integration test of your app. If you would like to just test them individually, it will require mocking everything and your assertions would be very hard as there could potentially use almost anything within the framework’s features.

May I ask, what you are trying to achieve?
What is the behavior you are trying to test?

I am assuming you are just trying to test the handlers and not unit testing the model objects, right?

Also, please note that you can intereact with the controller’s handler service and actually get instances of handler objects.

What would you like to see in terms of testing here? What improvements would you like?

Luis

Yeah, I’m not talking about the model objects those I can test outside of coldbox. What I was trying to do was to mock out the service layer call and just test the flow control, event and request collection portion of an event handler without actually hitting the service layer.

I was hoping to be able to mock out my getFooService method in the controller, either with mightmock (or coldmock) or injectMethod prior to the event handler executing. But to do that I need to get my hands on the instance that will be run by the execute method in the test.

I know I can accomplish this by setting up a mirror coldspring factory that just contains mocks, and having a coldbox.xml.cfm with a “test” environment that wired in the mocks instead of the real deal, that way when calling getPlugin(“ioc”).getBean(“fooService”) I’d get back a mockFooService. But i was hoping to avoid that extra configuration level.

I might just live with integration testing the handlers and not worry about unit testing them, but first I’ll investigate if the handler service will allow me to do this.

Thanks for that tip…

The handler service was exactly what I needed. I can call getRegisteredHandler, then mock out whatever I need before execute.

Thanks again…

Hey Jon,
  I wanted to throw out another take on the issue, for your enjoyment.
I see two obvious downsides with testing event handlers: 1)
performance, 2) your "action" handlers can junk up your database.

For #2, I can totally see where mocking would be appropriate. But for
all the "display" events, I'm thinking there might be some value in
ignoring the performance hit and actually using that to a better end
than just testing the controller's flow.

For starters, I'm just not sure I see much value in tests that
basically duplicate the controller's "flow" through mock verification.
Kind of seems redundant to me, to no significant benefit (emphasis on
significant). However, if you were to test them directly, you'd get
much more confidence, and also, you'd have the opportunity to see
performance trends over time.

The more I play with Hudson continuous integration, and the more I
simply read and listen to podcasts about CI in general, I'm definitely
seeing how you'd get good value from having the CI server do
performance trending, and then you can start doing things like failing
your "builds" if the delta on your test times exceeds a certain
threshold. So in this respect you take that lemon of performance hit
and turn it into lemonade... i.e. you can get a pretty good idea of
whether your app is performing as expected (admittedly under no load)
over the course of weeks and months.

With the tools these CI servers provide, you would potentially catch
overall system performance problems earlier b/c you'd start seeing
your build times increase, and since they hook into your source
control system, you would have a much easier time of pinpointing the
changes that led to the degradation.

Admittedly, I have zero experience in actually setting up a CI server
to do this, but it's all entirely possible with CF and MXUnit, and
since Luis has made unit testing event handlers with MXUnit so darn
easy, I'm thinking here might be a "win win" kind of deal.

Something to think about, at any rate.

Best,

marc

Wow, I will have to read marc’s post again, because my head felt like exploding for a bit!! Man you guys are testaholics!! I love it!!

Anyways, Jon, since 3.0 is on the horizon, how about a getHandler() method on the base mx unit test case, so it can retrieve a pointer to the handler in question? Then you don’t even need to use the execute() method, you can test the handler a la carte, I would inject it with a mock controller already. You would just have to pass in the event context manually on the method calls to test.

Any thoughts on this?

I was actually talking about this behavior with Billy Shelton (A true mocking genius), about the possibility of accomplishing this on the controller layer. Where as of now, you can do full top-down testing on the handler layer, but not really a handler unit test. We where debating whether it was something that could be benefitial or not. I still don’t know the answer, but after seeing this post, then it makes me think again, of how to offer this ability and make handler testing, SIMPLE and EASY!!

Any ideas?

I definitely like how easy ColdBox makes it to do integration tests on the event handlers. And I am also fairly new to unit testing, so I may be on the wrong track trying to unit test them instead of just doing integration tests, although I didn’t intend for the unit tests to supplant integration tests.

But I do see value in asserting that the request context is set up correctly given certain inputs, I don’t know how many times I’ve wasted 15-20 minutes trying to hunt down why a view wasn’t doing what it should, only to find I hadn’t fired a response event or I hadn’t set some variable (albiet in flex which is where most of my unit testing experience is).

But for unit testing event handlers to be useful (and responsive) we do need to be able to easily mock out the external calls. Which is fairly easy, now that I realize I can use the HandlerService.

But to your question Louis, at first glance (to me an admitted newb to unit testing) what you suggest does sounds useful. I would wonder how you would determine which event handler is being tested though? Configure it in setup? I know CB is convention based, but mxunit needs a bit of specificity. I would defer to Marc and other more experienced unit testers there.

Marc, I would love to get to the point where we are doing continuous integration tests and automated regression tests, I will definitely look into Hudson. I really like the idea of performance trending with CI, that hadn’t really occured to me, but has obvious potential benifits in pointing out newly introduced bottlenecks.

Anyway I’ve got what I need to try out unit testing my event handlers. I might just conclude what Marc suggests and end up just doing the integration tests. We’ll see…

Thanks gusy.

Well,

I can very easily add methods to the base case so you can retrieve an event handler with no set dependencies, so you can mock it just on functionality. We already have on 3.0 a mockModel() method that does this, so this would be trivial

mockHandler(‘handler’)

This will return to you a decorated (by MockBox) handler that you can use to mock its dependencies, etc, so you can test, its methods. The handler will be given back to you with our mock Controller already setup so you can still use the request context for assertions, so a handler behavior test could look like this:

function setup(){
//get handler
handler = mockHandler(handler:"users’);

//mock service, let’s say it is a model integration, for ioc, you will need another approach
mockService = mockModel(name=‘UserService’,clearmethods=true);
//inject mock service into handler via MockBox
handler.$property(“UserService”,mockService,“instance”);
//setup requests on each test, this could be moved to a super method call
setupRequest();

}

//test the list method on the handler
function testList(){
//get context
event = getRequestContext();
//test Handler Method
results = handler.list(event);
//Assertions Here

}

What do you think??