I'm building a class library that will have some public & private methods. I want to be able to unit test the private methods (mostly while developing, but also it could be useful for future refactoring).
What is the correct way to do this?
I'm building a class library that will have some public & private methods. I want to be able to unit test the private methods (mostly while developing, but also it could be useful for future refactoring).
What is the correct way to do this?
If you want to unit test a private method, something may be wrong. Unit tests are (generally speaking) meant to test the interface of a class, meaning its public (and protected) methods. You can of course "hack" a solution to this (even if just by making the methods public), but you may also want to consider:
In the rare cases I have wanted to test private functions, I have usually modified them to be protected instead, and the I have written a subclass with a public wrapper function.
The Class:
...
protected void APrivateFunction()
{
...
}
...
Subclass for testing:
...
[Test]
public void TestAPrivateFunction()
{
APrivateFunction();
//or whatever testing code you want here
}
...
Well you can unit test private method in two ways
you can create instance of PrivateObject class the syntax is as follows
PrivateObject obj= new PrivateObject(PrivateClass);
//now with this obj you can call the private method of PrivateCalss.
obj.PrivateMethod("Parameters");
You can use reflection.
PrivateClass obj = new PrivateClass(); // Class containing private obj
Type t = typeof(PrivateClass);
var x = t.InvokeMember("PrivateFunc",
BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Public |
BindingFlags.Instance, null, obj, new object[] { 5 });
I've also used the InternalsVisibleToAttribute method. It's worth mentioning too that, if you feel uncomfortable making your previously private methods internal in order to achieve this, then maybe they should not be the subject of direct unit tests anyway.
After all, you're testing the behaviour of your class, rather than it's specific implementation - you can change the latter without changing the former and your tests should still pass.
MS Test has a nice feature built in that makes private members and methods available in the project by creating a file called VSCodeGenAccessors
[System.Diagnostics.DebuggerStepThrough()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TestTools.UnitTestGeneration", "1.0.0.0")]
internal class BaseAccessor
{
protected Microsoft.VisualStudio.TestTools.UnitTesting.PrivateObject m_privateObject;
protected BaseAccessor(object target, Microsoft.VisualStudio.TestTools.UnitTesting.PrivateType type)
{
m_privateObject = new Microsoft.VisualStudio.TestTools.UnitTesting.PrivateObject(target, type);
}
protected BaseAccessor(Microsoft.VisualStudio.TestTools.UnitTesting.PrivateType type)
:
this(null, type)
{
}
internal virtual object Target
{
get
{
return m_privateObject.Target;
}
}
public override string ToString()
{
return this.Target.ToString();
}
public override bool Equals(object obj)
{
if (typeof(BaseAccessor).IsInstanceOfType(obj))
{
obj = ((BaseAccessor)(obj)).Target;
}
return this.Target.Equals(obj);
}
public override int GetHashCode()
{
return this.Target.GetHashCode();
}
}
With classes that derive from BaseAccessor
such as
[System.Diagnostics.DebuggerStepThrough()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TestTools.UnitTestGeneration", "1.0.0.0")]
internal class SomeClassAccessor : BaseAccessor
{
protected static Microsoft.VisualStudio.TestTools.UnitTesting.PrivateType m_privateType = new Microsoft.VisualStudio.TestTools.UnitTesting.PrivateType(typeof(global::Namespace.SomeClass));
internal SomeClassAccessor(global::Namespace.Someclass target)
: base(target, m_privateType)
{
}
internal static string STATIC_STRING
{
get
{
string ret = ((string)(m_privateType.GetStaticField("STATIC_STRING")));
return ret;
}
set
{
m_privateType.SetStaticField("STATIC_STRING", value);
}
}
internal int memberVar {
get
{
int ret = ((int)(m_privateObject.GetField("memberVar")));
return ret;
}
set
{
m_privateObject.SetField("memberVar", value);
}
}
internal int PrivateMethodName(int paramName)
{
object[] args = new object[] {
paramName};
int ret = (int)(m_privateObject.Invoke("PrivateMethodName", new System.Type[] {
typeof(int)}, args)));
return ret;
}
On CodeProject, there is an article that briefly discusses pros and cons of testing private methods. It then provides some reflection code to access private methods (similar to the code Marcus provides above.) The only issue I've found with the sample is that the code doesn't take into account overloaded methods.
You can find the article here:
Declare them internal, and then use the InternalsVisibleToAttribute to allow your unit test assembly to see them.
I tend not to use compiler directives because they clutter things up quickly. One way to mitigate it if you really need them is to put them in a partial class and have your build ignore that .cs file when making the production version.
CC -Dprivate=public
"CC" is the command line compiler on the system I use. -Dfoo=bar does the equivalent of #define foo bar. So, this compilation option effectively changes all private stuff to public.
Here is good article about unit testing of private methods. But I'm not sure what's better, to make you application designed specially for testing(it's like creating tests for testing only) or use reflexion for testing. Pretty sure most of us will choose second way.
For JAVA language
Here, you can over-ride a particular method of the testing class with mock behavior.
For the below code:
public class ClassToTest
{
public void methodToTest()
{
Integer integerInstance = new Integer(0);
boolean returnValue= methodToMock(integerInstance);
if(returnValue)
{
System.out.println("methodToMock returned true");
}
else
{
System.out.println("methodToMock returned true");
}
System.out.println();
}
private boolean methodToMock(int value)
{
return true;
}
}
Test class would be:
public class ClassToTestTest{
@Test
public void testMethodToTest(){
new Mockup<ClassToTest>(){
@Mock
private boolean methodToMock(int value){
return true;
}
};
....
}
}