views:

81

answers:

4

I'm getting started with unit testing and trying to do some TDD. I've read a fair bit about the subject and written a few tests. I just want to know if the following is the right approach.

I want to add the usual "contact us" facility on my web site. You know the thing, the user fills out a form with their email address, enters a brief message and hits a button to post the form back.

The model binders do their stuff and my action method accepts the posted data as a model. The action method would then parse the model and use smtp to send an email to the web site administrator infoming him/her that somebody filled out the contact form on their site.

Now for the question .... In order to test this, would I be right in creating an interface IMessageService that has a method Send(emailAddress, message) to accept the email address and message body. Implement the inteface in a concrete class and let that class deal with smtp stuff and actually send the mail.

If I add the interface as a parameter to my controller constructor I can then use DI and IoC to inject the concrete class into the controller. But when unit testing I can create a fake or mock version of my IMessageService and do assertions on that.

The reason I ask is that I've seen other examples of people generating interfaces for SmtpClient and then mocking that. Is there really any need to go that far or am I not understanding this stuff?

+1  A: 

The aproach you describe has worked well for me in the past. I worked on a project that interfaced with the MS Dynamics CRM web service API. I wanted to unit test my code but i had no desire to unit test the web service. I followed the exact process you describe but with the web service mocked rather than the mail delivery. It worked very well.

Ben Robinson
+2  A: 

You'd still need to test your class that invokes the mailer. I suggest that you might want to do a little of both. I typically create an IMailClient interface and a wrapper around SmtpClient that implements the interface. Use (and inject) the interface in a proxy class that knows how to construct the message and send it (it might have several factory-type methods that can construct multiple different types of messages). The shim around the SmtpClient really should be just that, thus there's little need for unit testing it. You can mock your shim when testing the proxy class and mock your proxy class when testing your controllers.

tvanfosson
I agree, and it will probably come in handy as soon as you need that IMailClientAsync t that you can swap in.
Hal
+1  A: 

You are on the right track, that's the approach you should be using. Probably the examples you are referring to, is people going at it the hard/wrong way ... or are examples on how you can deal with a large legacy code base.

Injecting the mechanism to deliver the message is flexible, and its easily reuse in other scenarios. One such scenario is diagnostics, if you have a dev server you probably don't want it to be hitting mails all the time, by switching the injected class you can have it output to a file or just simple Debug.Write.

ps. you're still recommended to test your SmptDeliver class, but that'd be a focused integration test that you can do on that class independently of the rest of the code.

eglasius
+1  A: 

I think your on the right track. Don't worry about smtp servers or anything else. Just unit test what you need. Let the tests tell you what you need. When you get to the testing of the actual Send(emailAddress, message), then you can worry about how you will actually send the message to the admin.

Gutzofter