我正在尝试编写一个单元测试来测试抽象类中的受保护方法。我已经尝试编写一个继承自抽象类的测试类,但是当我实例化测试类时,基本抽象类尝试连接到Oracle数据库并失败,这使我无法测试我感兴趣的受保护方法in。抽象类不能修改。
如何在此抽象类中直接对受保护的方法进行单元测试?
以下是我尝试反思的片段。
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];
答案 0 :(得分:3)
可行,但请注意您的代码可能存在几个严重问题:
这是一个食谱:
FormatterServices.GetUninitializedObject
获取类的实例而不调用构造函数。ProtectedMethod
。通过这种方式,您可以测试ProtectedMethod
:
这是一个示例代码:
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
}
答案 1 :(得分:1)
妥协。
说你有:
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
}
}
将其更改为:
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
}
}
现在,您可以在TestableClass
中测试要测试的行为。对于WantToTestThis
类,应对可怕遗留代码的压力,并且不测试它。使用最少量的未经测试的代码插入可测试的东西是一个历史悠久的策略;我第一次听到Michael Feather的书Working Effectively with Legacy Code。
答案 2 :(得分:0)
我认为最好的解决方案就是在评论中提出要打破这个阶级。
然而,如果您想在不更改类的情况下测试它,可以将构造函数的内容移动到虚拟方法中:
public abstract class TheOracleOne
{
protected virtual void Init()
{
// connection things
}
}
在派生类中重写并不执行任何操作:
public class TestClass : TheOracleOne
{
protected override void Init()
{
}
}
这应该跳过在抽象类的构造函数中发生的初始化,允许您在派生类上正常访问该方法。