tags:

views:

91

answers:

4

It seems to me that some code is easier to unit test than others. I love writing unit tests for highly functional code (by this, I'm referring to functions that primarily operate on their arguments and return computed results).

But, when the code is much more about it's side effects, testing it becomes much harder. For example, a socket class I use at work has a method declared like this:

void Socket::Create( void );

It takes no arguments, and returns no results. On error it throws, but the direct result of the underlying call (socket()) is hidden by the class itself.

Can anyone recommend techniques or perhaps a book, or a website to learn more advanced techniques for unit testing code that is mostly about its side effects?

+1  A: 

It would be my opinion that you shouldn't care what it does, only that it works. So, you don't need to test that method, you just need to make sure that the underlying operation that you are trying to perform succeeds. If it does, then all is well, if it doesn't, then you need to fix something. This can be tested.

My opinion is probably not inline with "TDD" though, so take it for what it's worth.

Noon Silk
+2  A: 

I'll throw this out there but I don't think it will help with your specific example. There is a general concept called Dependency Injection or Inversion of Control that allows you to take infrastructure dependencies out of your business logic. So let's say you have a routine called SubmitLoanApplication that does validation, performs business logic, and ultimately submits data to the database. Running a unit test against this is difficult - but with IoC you are able to code your business logic against an interface and you pass in an instance of that interface that the business logic ultimately operates on. In your production code - that instance connects to the database. In your unit test code - that instance is static and your calls return predictable results.

Mayo
Interesting. This is exactly the kind of thing I am looking for.
dicroce
@dicroce: Think about it though. If you do this, what exactly are you testing? You're testing a method call. You're not testing the live implementation. Kind of useless, as described, IMHO.
Noon Silk
+1. @Noon: You still need to integrate or functional test the socket/DB/whatever, but IoC lets you test your other classes in isolation, quickly, and with minimal setup fixtures.
TrueWill
@TrueWill: Yeah, but read the original question. He wants to test the implementation. This will not do that.
Noon Silk
+1  A: 

I am not sure if you want to test the method Socket::Create( void ) or code that calls this method. In the first case you want to write tests for existing functionality. So you might want to read...

http://www.objectmentor.com/resources/articles/WorkingEffectivelyWithLegacyCode.pdf

or better the book...

http://www.amazon.com/Working-Effectively-Legacy-Michael-Feathers/dp/0131177052

In the second case you need a Test Double (we were once allowed to call them mocks...) for the underlying call. See...

http://xunitpatterns.com/

both books deal exactly with the kind of problem you mention. In short, the solution is to divide the problem in such a way that most functionality is easily testable and only as little as possible is not.

Sebastian Kübeck
A: 

As you expose this, what it seems is that you need some grey-box testing in here.

You would treat this method as a black-box within your unit test.

  • You set the environment for a successful call to this method
  • You see how things are.
  • You call this method.
  • You check if things have changed in the way you expect.

  • You set the environment for a failed call to this method

  • You call this method
  • You check that it has thrown the expected exception
EKI