Reputation: 73
I have to write a unit test for an internal or private method in an abstract class in c#. consider this:
Public Abstract Class MyAbstractClass
{
Private String MyMethod()
{
//Do Something
return "HI";
}
}
And, my test method:
public void MyTestMethod()
{
var testProcessor = new Mock<MyAbstractClass>
{
CallBase = true
};
var privateType = new PrivateType(typeof(MyAbstractClass));
PrivateObject privateObject = new PrivateObject(testProcessor , privateType);
var resValue = (String)privateObject.Invoke("MyMethod");
Assert.AreEqual(resValue ,"HI");
}
but when I run the test method, I'm getting below error:
System.Reflection.TargetException: Object does not match target type.
How to resolve that?
Upvotes: 5
Views: 2517
Reputation: 2463
Assuming you are using Moq as a mocking tool, the exception shown results of passing testProcessor
instead of testProcessor.Object
. If you change that line to...
PrivateObject privateObject = new PrivateObject(testProcessor.Object, privateType);
...you'll get rid of this error.
This is how it should work (in NET Framework, PrivateObject and such like has not been ported to NET Core MSTest):
//productive code
public abstract class MyAbstractClass
{
private string MyMethod()
{
//Do Something
return "HI";
}
}
//testproject
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
var testProcessor = new Moq.Mock<MyAbstractClass>();
var privateType = new PrivateType(typeof(MyAbstractClass));
var privateObject = new PrivateObject(testProcessor.Object, privateType);
var resValue = (string)privateObject.Invoke("MyMethod");
Assert.AreEqual(resValue, "HI");
}
}
By the way, I' didn't know a mock of an abstract class will execute the implementation of the abstract class. I thought it would create stubs that return defaults, as a mock of an interface does.
Interesting feature...
Upvotes: 2
Reputation: 5165
You should not be testing private methods:
I do not unit test private methods. A private method is an implementation detail that should be hidden to the users of the class. Testing private methods breaks encapsulation.
See this post for more details.
As Flydog57 says, you should be testing a derived class (not the abstract one).
You can do this easily by creating a private test class inside your test class, and use this private class in your tests.
private class MyConcreteTestClass : MyAbstractClass
{
public string SomeMethodThatCallsMethodInAbstractClass()
{
....
}
}
public void MyTestMethod()
{
// Arrange
var testProcessor = new MyConcreteTestClass();
// Act
var result = testProcessor.SomeMethodThatCallsMethodInAbstractClass();
// Asset
Assert.AreEqual(result ,"HI");
}
Upvotes: 4
Reputation: 9666
You need to specify the BindingFlags
to be NonPublic
in order to find the private method.
I am not sure what is the PrivateObject
but this should work (you may change it a little bit to make it suitable for your needs):
Type type = typeof(MyAbstractClass);
MethodInfo method = type.GetMethod(
methodName, BindingFlags.NonPublic | BindingFlags.Instance);
string result = (string)method.Invoke("MyMethod", null);
Upvotes: 0