[英]Unit Test protected method of an abstract class
I'm trying to write a unit test to test a protected method in an abstract class. 我正在尝试编写单元测试来测试抽象类中的受保护方法。 I've tried writing a test class that inherits from the abstract class, but when I instantiate the test class the base abstract class attempts to connect to an Oracle database and fails which doesn't allow me to test the protected method I'm interested in. The abstract class cannot be modified. 我已经尝试编写一个继承自抽象类的测试类,但是当我实例化测试类时,基本抽象类尝试连接到Oracle数据库并失败,这使我无法测试我感兴趣的受保护方法in。抽象类不能修改。
How can I directly unit test a protected method in this abstract class? 如何在此抽象类中直接对受保护的方法进行单元测试?
Here is snippet of what I tried with reflection. 这是我尝试反思的片段。
Type type = typeof(AbstractClass);
BindingFlags eFlags = BindingFlags.Instance | BindingFlags.NonPublic;
MethodInfo myMethod = type.GetMethod("ProtectedMethod", eFlags);
object[] arguments = new object[] { _myDs };
myMethod.Invoke(type, arguments);
_myDs = (DataSet)arguments[0];
It is doable , but please note there may be couple of serious problems with your code: 它是可行的 ,但请注意您的代码可能有几个严重的问题:
Here's a recipe: 这是一个食谱:
FormatterServices.GetUninitializedObject
for getting instance of the class without calling constructor. 然后,调用FormatterServices.GetUninitializedObject
来获取类的实例而不调用构造函数。 ProtectedMethod
. 之后,您可以使用反射来调用ProtectedMethod
。 By that, you are able to test ProtectedMethod
: 通过这种方式,您可以测试ProtectedMethod
:
And here is an example code: 这是一个示例代码:
class AbstractClassFake : AbstractClass { }
[Test]
public void Test()
{
// Arrange:
var abstractClassFake = (AbstractClassFake)FormatterServices
.GetUninitializedObject(typeof(AbstractClassFake));
MethodInfo method = abstractClassFake.GetType()
.GetMethod("ProtectedMethod",
BindingFlags.Instance | BindingFlags.NonPublic);
object[] arguments = new object[] { myDs };
// Act:
object val = method.Invoke(abstractClassFake, new[] { myDs });
// Assert:
// TODO: Your assertion here
}
Compromise. 妥协。
Say you have: 说你有:
public abstract class CanNeverChange
{
public CanNeverChange()
{
//ACK! connect to a DB!! Oh No!!
}
protected abstract void ThisVaries();
//other stuff
}
public class WantToTestThis : CanNeverChange
{
protected override void ThisVaries()
{
//do something you want to test
}
}
Change it to this: 把它改成这个:
public class WantToTestThis : CanNeverChange
{
protected override void ThisVaries()
{
new TestableClass().DoSomethingYouWantToTest();
}
}
public class TestableClass
{
public void DoSomethingTestable()
{
//do something you want to test here instead, where you can test it
}
}
Now you can test the behavior you want to test in TestableClass
. 现在,您可以在TestableClass
中TestableClass
要测试的行为。 For the WantToTestThis
class, compromise to the pressure of terrible legacy code, and don't test it. 对于WantToTestThis
类,妥协于可怕遗留代码的压力,并且不测试它。 Plugging in a testable thing with a minimal amount of untested code is a time honored strategy; 使用最少量的未经测试的代码插入可测试的东西是一个历史悠久的策略; I first heard of it from Michael Feather's book Working Effectively with Legacy Code . 我第一次听到Michael Feather的书“有效地使用遗留代码”一书。
I think the best solution is to break the class apart as the comments suggest. 我认为最好的解决方案就是在评论中提出要打破这个阶级。
However , if you would like to test it without changing the class very much, you could move the contents of the constructor into a virtual method: 但是 ,如果您想在不更改类的情况下测试它,可以将构造函数的内容移动到虚拟方法中:
public abstract class TheOracleOne
{
protected virtual void Init()
{
// connection things
}
}
And override in your derived class to do nothing: 并在派生类中覆盖以执行任何操作:
public class TestClass : TheOracleOne
{
protected override void Init()
{
}
}
This should skip the initialization that is taking place in the abstract class's constructor, allowing you to access the method normally on the derived class. 这应该跳过在抽象类的构造函数中发生的初始化,允许您在派生类上正常访问该方法。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.