简体   繁体   English

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

[英]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. 解决方案是创建一个派生自DisplayUnitDummyDisplayUnit并使用它。 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.

相关问题 使用 MS Fakes C# 对类中的静态方法进行单元测试 - Unit Test Static methods in a class using MS Fakes C# 用伪造品进行C#单元测试:何时以及如何设置/处置ShimsContext的idisposable…以及是否不……? - c# unit testing with fakes: when and how to setup/dispose ShimsContext's idisposable… and if I don't…? 如何在反射C#中调用单元测试类 - How to invoke unit test class in reflection c# C# 单元测试 - 您是否应该对基类中处理的派生类中的某些内容进行单元测试? - C# Unit Testing - Should you unit test something in a derived class that is taken care of in a base class? 需要为使用C#在Microsoft单元测试工具中处理接口结果的类创建伪造品 - Need to create fakes for a class that manipulates the results of interface in microsoft unit testing tool using c# 使用C#和反射对类进行单元测试属性 - Unit testing properties of a class using C# and reflection 对使用RegistryManager C#Azure IoTHub的类进行单元测试 - Unit Testing a class that uses RegistryManager C# Azure IoTHub 利用伪造品自动化单元测试DbContext和集成测试 - Automate Unit Testing DbContext and Integration Test With Fakes 如何使用Microsft Fakes框架对抽象类进行单元测试 - How to unit test an abstract class using Microsft Fakes framework C# 单元测试:使用使用网络的 API 时出现 UnauthorizedAccessException - C# unit test: UnauthorizedAccessException when using API that uses network
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM