繁体   English   中英

当您正在测试的类在C#中使用反射时,如何使用fakes进行单元测试

[英]How to Unit Test with fakes when the class you're testing uses reflection in C#

我正在尝试对使用反射来构造从已知基类派生的未知对象的工厂类进行单元测试。

但是,当工厂尝试调用从我的假单位类型派生的构造函数时,我得到一个异常。 这是一个空引用异常。

我正在使用FakeItEasy。 这是我在这里发生的事情:

[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 ());
    }

这个底线是我的问题。 DisplayUnit是一个抽象类。 除了构造函数之外,它的实现在这种情况下无关紧要。 但是,DisplayUnit有一个构造函数,需要将Dictionary作为参数。

如果我使用REAL类型(非伪造),代码工作正常。 (例如, A.CallTo(() => _plgin.DisplayUnitType).Returns(typeof(TextUnit));但是,真正的类型需要在我的核心代码之外的依赖。我希望在运行时添加不同类型的DisplayUnit作为插件。 因此,我想使用虚假的显示单元对我的DisplayUnitFactory进行单元测试。在这个测试中,我不需要依赖外部程序集来完成这项工作。

这是我的考试。

[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);
}

这是我的工厂代码:

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);
}

本质上,我需要伪造将使用Reflection出现的ConstructorInfo,并最终伪造ConstructorInfo.Invoke()的返回。 但是当调用构造函数时,我在getDisplayUnit()得到一个空引用异常,因为ctor返回null。

救命!

所以感谢布莱尔,我相信我已经找到了解决方案:根本不是假冒。

伪造的类型只有一个公共构造函数,带有参数Castle.DynamicProxy.IInterceptor[], Dictionary<System.String,System.String> 因此,当Reflection试图获得构造函数时,整个过程就会崩溃。

解决方案是创建一个派生自DisplayUnitDummyDisplayUnit并使用它。 这很好用,不需要假货。

我想有时候我会尝试抽象到我错过明显解决方案的地步......

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM