views:

123

answers:

3

Hi.

I often design system where I have a class in my system that has a bunch of protected methods. The protected methods are that because they should be accessible to specializations, and as such, I consider the protected methods to be a contract between my general class and any specialized classes.

Therefore I want to test that these methods behave correctly, so my unit tests will need to access the protected methods, something that is not possible in c#, except by using dirty hacks like reflection.

The solution I normally choose is that I create a specialized class inside my unit test that exposes these protected methods as public. Because I always keep the unit tests in a separate assembly, the system code itself does not have access to these classes, and inside my system code, the protected function remains protected.

// In the system code assembly
namespace MySystem {
    public class SomeClass {
        protected void DoSomething() {
            ...
        }
    }
}

// In the unit test assembly
namespace MySystem.Unittests {
    public class SomeClass2 : SomeClass {
        public new void DoSomething() {
            base.DoSomething();
        }
    }
}

My unit test is now able to test the behaviour of the protected member on the parent class by instantiating the specialized class.

I also use this even further to be able to mock the object and mock function calls to protected virtual functions, but that code is a little more complex, so I'll just cut that out.

I find this way of accomplishing this task to be so straight forward that I cannot possibly be the only person doing this, and so I assume that there must be a common naming convention for this?

+1  A: 

Don't know of a pattern name for whaty you are doing, but .net has a solution for this... Make the methods protected internal, and then add the following to the projects assemblyInfo file

[assembly: InternalsVisibleToAttribute("[FQN of TestAssembly]")]

This will make the internal methods in the project visible to the test assembly specified in the attribute

Charles Bretana
+2  A: 

I'm not sure that I see the point, generally, in testing your protected methods, though, I'm speaking from a TDD point of view. Generally, your tests are written against the public methods of the class. Protected methods arise as you refactor code to extract common methods that are used internally. Since these arise from refactorings, your existing tests already cover the code being refactored. Later tests for code that uses the refactored methods via the public methods of specializations also test the code -- in this case that the public methods of the specialization work properly when using the common, protected methods.

In the few cases where an explicit test for a protected method makes sense, I don't see the harm in using reflection to conduct the test. You're only breaking encapsulation for the purpose of the test after all.

tvanfosson
+1  A: 

I have only done this when I don't control the class needed to be tested. Charles points out what you can do in .NET when you control the source code.

Your case is a bit different in that your class is intended to be used as a superclass, so testing it via a subclass makes a lot of sense (since the class isn't intended to stand on its own). In this case, you are basically doing a variant of Test-Specific Subclass. The pattern described in the link is more about overriding behavior, and is very useful if you have a class that was not written test first and has a high coupling, it is a good way to tease apart the dependency (usually as an intermediate step to getting a separate class passed as a parameter). In your case, the "overriding" is for the purpose if increasing access, but it seems to fit the same pattern.

Yishai
Actually after reading the description of the pattern, I would say that Test-specific subclass is exactly what I do. The pattern describes the "behavior exposing sub-class" as an example of Test-specific sub-class. I was not aware of that site, but it looks awesome, and I think that in there I'll find inspiration for building better test code, thanks for that! (I ordered the book already)
Pete