"Internal" Unit Tests / Conditionally Suppressing CIL Compilation

Mike_R

Junior Contributor
Joined
Oct 20, 2003
Messages
316
Location
NYC
I have nothing against NUnit or the like, I think that these unit-testing programs really are excellent...

But more and more it's been bothering me that the testing code is separate from the class that is being testing. So I decided to put my testing code for each class within an internal, nested class named "Tester", nested within the class being tested. I then use the assembly:InternalsVisibleToAttribute to enable my testing assembly -- and only my testing assembly -- to have access to this testing code. So far, so good...

However, for my last step, I would like to prevent this testing code from being emitted to CIL when compiled as a release build. My first thought was to use the [Conditional("DEBUG")] attribute, however, the ConditionalAttribute cannot be used with methods that have a non-void return value, nor with methods that have out parameters. :(

Using partial methods would be extremely awkward, and would suffer from the same problem...

My only other thought is to use the [Conditional("DEBUG")] attribute using void methods and return my results to a static global field. Since all my testing is single threaded anyway, this would work fine... But it does feel pretty crude. :(

Does anyone have any other ideas? Is there any other way to suppress a method from being compiled to the CIL?

Thanks guys, in advance...
Mike
 
I usually wrap my unit test classes in conditional compilation blocks so they aren't compiled in release mode. It cuts down the size of my assemblies a little and helps easily trim the clutter on sandcastle generated documentation files.

In C# it looks like:
C#:
#if DEBUG

 // Code you want only in Debug builds here

#endif

In VB.Net it looks like
Visual Basic:
#If DEBUG Then

   ' Code you want only in Debug builds here

#End If

The cool thing about conditional compilation is that you can also declare other compiler level variables if you wanted to get fancy. So, you could have a Release build with Unit Tests only under certain, specific conditions if you really wanted to.

I must say, the method you have taken for writing unit tests (internal with internal visible attributes) seems rather complicated. Did you run into problems with other unit test implementation techniques or do you just like having the tests as physically close to the implementation as possible?
 
Ah, thank you mskeel! Using #if DEBUG ... #endif blocks will definitely be the way to go for me. I did not realize that the #if directive could be used to surround an entire class. This is beautiful and does exactly what I need. (I had thought that it could only be used within a method.)

I must say, the method you have taken for writing unit tests (internal with internal visible attributes) seems rather complicated.
Maybe, I'm not quite decided on this yet. I am just taking around the idea at this point. But I think that it makes a lot of sense at a lot of levels...

Did you run into problems with other unit test implementation techniques or do you just like having the tests as physically close to the implementation as possible?
I have no real problems with NUnit or the like. But, yes, the main idea I'm shooting for here is to have the testing code be as physically close to the implementation as possible. It makes it easier to make and test, and it makes everything more portable: if I copy and paste, or re-factor and move the class, the test code moves right with the class that is being tested.

Since NUnit works using reflection, keying on various attributes, I wonder if I might be able to simply use NUnit and still use internal, nested testing classes. I've not tested this though -- since NUnit uses reflection, a public class should not be required here, but it is possible that it still respects public vs private/internal and only executes public classes that have the correct attributes? But I don't know...

Also since NUnit's methods are also void methods, without any out parameters, if this works then I could simply use a [Conditional("DEBUG")] attribute for each method in the class in this case. However, your idea to use #if ..#endif blocks to surround the entire class and more effective.

Anyway, just thinking out loud at the moment, I guess...

Mike
 
Back
Top