I would love some input on this from you fellow developers out there, as this is something I continue to try and improve on… WARNING, CODE BELOW THE BREAK!
(Note, I just realized the inline images here are overlapping like hell. Sorry, I’ve changed them to also be links you can click to view completely)
I have to admit that I often struggle with finding the right balance of unit testing, test driven development, what code to unit-test, how much to test it, etc.. A huge portion of code goes (formally/automated-)untested because it’s in the UI and there just aren’t great ways for testing UIs. Due to the unit testing I have setup for the core Chef codebase, most of the bugs that get reported to me have their roots in the UI layer. That says a lot for how helpful unit testing has been for me, but isn’t very comforting when I go to release new versions since I don’t have a way to verify the UI other than manually trudging through everything and testing before each release.
On Chef I think I am balancing this better than I have in the past but I still run up against things that I just am not sure how to tackle with unit testing. I’ll explain.
Due to preference, I have all of the product code completely independent of any unit testing framework and code (NUnit references, test case fixture, etc). I have a single assembly (Chef.Test.dll) which references the Chef api and is where all of my test cases live. Last night I was working on some new features in Chef and found myself needing to unit test a class that I’m going to want to be Private. With my testing setup, the only way I can unit test this code would be to make it Public. So here’s what I compromised with:
3) In my test case, I can now access the collection I didn’t want to expose.
Before I went to write this up, it was considerably more ugly. I had the following setup to get access to the collection:
I couldn’t stand looking at that ugly syntax so I went with the Conditional attribute, with a cost of making the test case slightly more ugly by forcing the use of a Ref parameter. It’s still far better than what I started with.
This was the first time I’ve used Conditional, so I got to learn a few things about it:
- It cannot be applied to properties, so I had to make GetTokenDictionary instead of a property called TokenDictionary
- It has to be a Void method, so I couldn’t just return the collection
- It cannot use Out parameters, so I had to use Ref (I was getting worried that Ref wasn’t going to be possible, making the whole thing useless to me here)
I could have just used DEBUG, but as those of you who have worked with me in the past know, I tend to like things to be as explicit as possible. I want to have to say “USE THIS ONLY WITH NUNIT, FOOL!”. That’s just how I am.
You may be wondering what the big deal is with exposing that Method/collection as a Public method. Part of it is just OO purism I suppose – it doesn’t need to be exposed, so why should I be forced to?! The other part is due to the obfuscator I run the assemblies through after they get compiled. How I have it configured, some things wouldn’t get mangled if they were Public, and simply exposing that collection as Public would have forced the class TimeUnit to ALSO be public. Which I also didn’t want.
My question is, how have you guys tackled something like this before? I’m open to ideas, I’d love to learn a better way.