[英]How to Unit Test with fakes when the class you're testing uses reflection in C#
I'm trying to unit test a factory class that uses reflection to construct an unknown object that derives from a known base class. 我正在尝试对使用反射来构造从已知基类派生的未知对象的工厂类进行单元测试。
However, I'm getting an exception when the factory tries to invoke the the constructor derived from my fake unit's type. 但是,当工厂尝试调用从我的假单位类型派生的构造函数时,我得到一个异常。 It's a null reference exception. 这是一个空引用异常。
I'm using FakeItEasy. 我正在使用FakeItEasy。 Here's What I have going on here: 这是我在这里发生的事情:
[TestFixture]
public class DisplayUnitFactoryTests
{
private readonly IDisplayUnitPluginContainer _mgr = A.Fake<IDisplayUnitPluginContainer>();
private readonly DisplayUnitPlugin _plgin = A.Fake<DisplayUnitPlugin> ();
private DisplayUnit _unit;
private Guid _guid;
[TestFixtureSetUp]
public void init()
{
_unit = A.Fake<DisplayUnit> (p=> p.WithArgumentsForConstructor(new object[]{new Dictionary<string,string>()}));
_guid = Guid.NewGuid ();
A.CallTo (() => _mgr.Resolve (VALID_STRING)).Returns (_plgin);
A.CallTo (() => _mgr.Resolve (INVALID_STRING)).Returns (null);
A.CallTo (() => _plgin.DisplayUnitType).Returns (_unit.GetType ());
}
That bottom line is my issue. 这个底线是我的问题。 DisplayUnit is an abstract class. DisplayUnit是一个抽象类。 It's implementation shouldn't matter in this situation except for its constructor. 除了构造函数之外,它的实现在这种情况下无关紧要。 However, DisplayUnit has a constructor that requires a Dictionary as a parameter. 但是,DisplayUnit有一个构造函数,需要将Dictionary作为参数。
If I use a REAL type (not faked), the code works fine. 如果我使用REAL类型(非伪造),代码工作正常。 (eg A.CallTo(() => _plgin.DisplayUnitType).Returns(typeof(TextUnit));
However, That real type requires a dependency outside my core code. I want different types of DisplayUnits to be added at runtime as plugins. Thus, I want to unit test my DisplayUnitFactory using a fake Display Unit. In this test, I shouldn't need to depend on an outside assembly in order to make this work. (例如, A.CallTo(() => _plgin.DisplayUnitType).Returns(typeof(TextUnit));
但是,真正的类型需要在我的核心代码之外的依赖。我希望在运行时添加不同类型的DisplayUnit作为插件。 因此,我想使用虚假的显示单元对我的DisplayUnitFactory进行单元测试。在这个测试中,我不需要依赖外部程序集来完成这项工作。
Here's my test. 这是我的考试。
[Test]
public void InstantiateNew_ValidPluginID_EmptyDict_ReturnsCorrectDisplayUnit()
{
var factory = new DisplayUnitFactory (_mgr);
var du = factory.InstantiateNew (VALID_STRING, new Dictionary<string, string> ());
Assert.That (du, Is.Not.Null);
}
Here's my factory code: 这是我的工厂代码:
public DisplayUnit InstantiateNew (string pluginId, Dictionary<string, string> attributes)
{
return getDisplayUnit (pluginId, attributes);
}
private DisplayUnit getDisplayUnit(string pluginId, Dictionary<string,string> attributes)
{
//Get the constructor that accepts only a dictionary<string,string>.
var ctor = getCtor (pluginId, new Type[]{typeof(Dictionary<string,string>)});
//Invoke it with the attributes dictionary.
var unit = ctor.Invoke (new object[]{ attributes }) as DisplayUnit;
return unit;
}
private ConstructorInfo getCtor(string pluginId, Type[] paramTypes)
{
var plugin = _container.Resolve (pluginId);
if (plugin == null)
throw new NotRegisteredPluginException ("Plugin not registered: " + pluginId);
var type = plugin.DisplayUnitType;
return type.GetConstructor (paramTypes);
}
Essentially, I need to fake the ConstructorInfo that will come out using Reflection, and ultimately fake the return from ConstructorInfo.Invoke(). 本质上,我需要伪造将使用Reflection出现的ConstructorInfo,并最终伪造ConstructorInfo.Invoke()的返回。 But I'm getting a null reference exception in getDisplayUnit()
when the constructor is invoked, because the ctor
is coming back null. 但是当调用构造函数时,我在getDisplayUnit()
得到一个空引用异常,因为ctor
返回null。
Help! 救命!
So Thanks to Blair, I believe I've found the solution: It's not to use a Fake at all. 所以感谢布莱尔,我相信我已经找到了解决方案:根本不是假冒。
The faked type will have only a single public constructor, with arguments Castle.DynamicProxy.IInterceptor[], Dictionary<System.String,System.String>
. 伪造的类型只有一个公共构造函数,带有参数Castle.DynamicProxy.IInterceptor[], Dictionary<System.String,System.String>
。 Thus the whole process was breaking down when Reflection tried to get a constructor. 因此,当Reflection试图获得构造函数时,整个过程就会崩溃。
The solution was to create a DummyDisplayUnit
that derived from DisplayUnit
and use that instead. 解决方案是创建一个派生自DisplayUnit
的DummyDisplayUnit
并使用它。 This worked just fine, without needing a fake. 这很好用,不需要假货。
I guess sometimes I try to abstract to the point where I miss the obvious solution... 我想有时候我会尝试抽象到我错过明显解决方案的地步......
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.