views:

3292

answers:

5

I'm trying to Unit Test a class that has many internal functions. These obviously need testing too, but my Tests project is seperate, mainly because it covers many small, related projects. What I have so far is:

FieldInfo[] _fields = 
    typeof(ButtonedForm.TitleButton).GetFields(
        BindingFlags.NonPublic | BindingFlags.Instance | 
        BindingFlags.DeclaredOnly);
Console.WriteLine("{0} fields:", _fields.Length);
foreach (FieldInfo fi in _fields)
{
    Console.WriteLine(fi.Name);
}

This spits out all the private members nicely, but still doesn't display internals. I know this is possible, because when I was messing around with the autogenerated tests that Visual Studio can produce, it asked about something to do with displaying internals to the Test project. Well, now I'm using NUnit and really liking it, but how can I achieve the same thing with it?

+19  A: 

It would be more appropriate to use the InternalsVisibleTo attribute to grant access to the internal members of the assembly to your unit test assembly.

Here is a link with some helpful additional info and a walk through:

To actually answer your question... Internal and protected are not recognized in the .NET Reflection API. Here is a quotation from MSDN:

The C# keywords protected and internal have no meaning in IL and are not used in the Reflection APIs. The corresponding terms in IL are Family and Assembly. To identify an internal method using Reflection, use the IsAssembly property. To identify a protected internal method, use the IsFamilyOrAssembly.

spoon16
I agree with the use of InternalsVisibleTo, but thanks for the answer too :)
Matthew Scharley
No problem, it's good to have an actual explanation even if in your particular use case a different approach is more appropriate.
spoon16
Just an FYI, the page linked to in this answer is mine, and my URL has changed. That is why you might be getting a 404. Try this updated link http://jason.whitehorn.ws/2007/11/09/The-Wonders-Of-InternalsVisibleTo.aspx
Jason Whitehorn
Thanks Jason, I updated the link.
spoon16
Post has moved again, link updated again :)
Patrick McDonald
+3  A: 

Adding the InternalsVisibleTo assembly level attribute to your main project, with the Assembly name of thre test project should make internal members visible.

For example add the following to your assembly outside any class:

[assembly: InternalsVisibleTo("AssemblyB")]

Or for a more specific targeting:

[assembly:InternalsVisibleTo("AssemblyB, PublicKey=32ab4ba45e0a69a1")]

Note, if your application assembly has a strong name, your test assembly will also need to be strongly named.

Ash
+3  A: 

I think you need to ask whether you should write unit tests for private methods? If you write unit tests for your public methods, with a 'reasonable' code coverage, aren't you already testing any private methods that need to be called as a result?

Tying tests to private methods will make the tests more brittle. You should be able to change the implementation of any private methods without breaking any tests.

Refs:

http://weblogs.asp.net/tgraham/archive/2003/12/31/46984.aspx http://richardsbraindump.blogspot.com/2008/08/should-i-unit-test-private-methods.html http://junit.sourceforge.net/doc/faq/faq.htm#tests_11 http://geekswithblogs.net/geekusconlivus/archive/2006/07/13/85088.aspx

Mitch Wheat
What happens when a bug in these smaller functions occurs and suddenly 10 tests stop passing?
Matthew Scharley
Then you track it down! Should be that hard right?
Mitch Wheat
Depends on the situation I suppose, but wouldn't it just be easier to use, for instance, the suggested InternalsVisibleTo, to expose them and write more targetted tests?
Matthew Scharley
No, I don't believe that is the best way to go about it. If the private methods are re-usable, place them in a class and make them public.
Mitch Wheat
I test all of my internal methods. The only thing that might happen with over testing is a little wasted time.
spoon16
@spoon16 : but if no public method calls them, what's the point?
Mitch Wheat
The point is that something calls them, and you are testing that something can expect the right things. In my particular case, I'm trying to unittest some event based stuff, so I need to access internal PerformEvent() calls to fire the events manually.
Matthew Scharley
Basically if that internal method is shared or called my multiple publicly accessible members than it helps me identify the source of a problem more quickly if the tests for those public members starts to fail.
spoon16
@spoon16: if tracking something down is as hard as you suggest then maybe your classes don't adhere to the SRP? (Single Responsibilty Principle)
Mitch Wheat
IMO: public internal is still public, if you're writing up tests for your project, it can only help if you cover the internals too, since you're writing them. Unit tests shouldn't cover private, protected or internal protected, but internal public, yes.
Matthew Scharley
It's not a matter of being "so hard" it's a matter of being even easier if you have one more level of test coverage.
spoon16
+2  A: 

Your code is only showing fields - so I'd hope it wouldn't show any internal members, as fields should always be private IMO. (With the potential exception of constants.)

Does ButtonedForm.TitleButton actually have any non-private fields? If you're trying to find internal methods then obviously you need to be calling GetMethods (or GetMembers) to get at them.

As others have suggested, InternalsVisibleTo is very handy for testing (and almost solely for testing!). As for whether you should be testing internal methods - I certainly find it useful to be able to do so. I don't regard unit testing as being exclusively black-box testing. Often when you know that public functionality is implemented using a few internal methods connected in a simple way, it's easier to do thorough testing of each of the internal methods and some "pseudo-integration" tests on the public method.

Jon Skeet
You're right, I should have been calling GetMethods() anyway to start with. +1 tomorrow when I get more votes again. I'm new to the whole reflection thing, can you tell? :D I've got a small scripting language in the works sometime, I figure that'll get me up to speed on reflection well and truely...
Matthew Scharley
+1  A: 

A justification for using the InternalsVisible is under my circumstances. We purchase the source code to a Chart Control. We have found where we need to make some modifications to that source control and compile our own version. Now to ensure we did not break anything, there are some unit tests I need to write that need access to some internal fields.

This is a perfect case where the InternalsVisible makes sense.

I was wondering, though, what do you do if you do not have access to the source? How could you get to an internal field? .Net Reflector can see that code, but I guess it is just looking at the IL.

As someone else mentioned, in IL internal structures are called Assembly. You can use System.Reflection to access these Assembly variables
Matthew Scharley