【问题标题】:private members in Class with overload constructor C# Unit Test具有重载构造函数 C# 单元测试的类中的私有成员
【发布时间】:2014-09-11 20:52:46
【问题描述】:

如何在单元测试中访问私有成员?我尝试使用 PrivateObject,但重载构造函数在这里,我收到 _inkContainerValue 错误。我可以在不使用类对象的情况下访问私有成员吗?

  public class Pen
   {

    private int _inkContainerValue = 1000;

    #region Constructors

    public Pen(int inkContainerValue)
    {
        this._inkContainerValue = inkContainerValue;
    }

    #endregion
    }

}

【问题讨论】:

  • 通常你不应该测试你的私人成员。如果您的测试需要访问它们,那么您应该重新考虑您的设计。不过,当我没有那种奢侈时,我通常会使用反射。
  • 我知道如何使用反射,但我不能这样做,因为这里是构造函数重载
  • 访问字段和构造函数重载有什么关系?
  • 我回应@SriramSakthivel。无论使用哪个构造函数来创建对象,_inkContainerValue 字段都将具有传递给被调用构造函数的inkContainerValue 参数的值。代码中有三个位置设置了值(不包括冗余字段初始值设定项),但对于任何给定的对象,只有其中一个位置被调用。
  • 我认为有人只是忘记声明一个没有参数的构造函数。正如@phoog 所说,如果没有在构造函数中声明 1000,我无法将 _inkContainerValue 设为 1000。当然,在尝试获取时这里没有关系一个类的成员,但我绝对做不到,因为没有没有参数的构造函数。悖论

标签: c# unit-testing private-members constructor-overloading


【解决方案1】:
PrivateObject pObj = new PrivateObject(typeof(Pen));
int privateInkContainerValue = (int)pObj.GetField("_inkContainerValue");

尝试上面的代码,通过单元测试中的 PrivateObject 类获取 _inkContainerValue 字段的值。

// Following is overloaded version to pass value to actual Pen class's constructor.
PrivateObject pObj = new PrivateObject(typeof(Pen), new object[]{12});
int privateInkContainerValue = (int)pObj.GetField("_inkContainerValue");

我现在没有编辑器。语法应该可以正常工作。

【讨论】:

  • 我使用的第一个代码,但 p0bj 出现错误。第二个不能正常工作,因为 privateInkContainerValue 的值为 12
  • 你能看一下吗?
  • 第二个有效,因为 12 作为值传递给您的第一个构造函数。将 12 替换为您自己的变量/值,您应该可以测试结果。
  • 我想得到这个 1000,但不把 1000 添加到新对象[]{/*1000*/};
【解决方案2】:

我可以在不使用类对象的情况下访问私有成员吗?

没有。您必须拥有一个对象实例才能从该对象中提取数据。

无意冒犯,但由于构造函数重载,您对使用反射的犹豫似乎没有实际意义。如果你有一个实例,它不应该阻止你使用反射,如果你没有,它不应该阻止你使用反射。

这是一个使用反射从_ink 获取值的示例。它还向您展示了如何在不使用构造函数的情况下获取实例。但是,请记住 nothing 将被初始化。 _ink 将是 0 而不是 1000,正如您在代码中看到的那样。

public class Pen
{
    int _ink = 1000;

    public Pen(int ink)
    {
        _ink = ink;
    }
}

void Test()
{
    //Create the object and check constructor set the value
    var pen = new Pen(5);
    var field = pen.GetType().GetField("_ink", BindingFlags.NonPublic|BindingFlags.Instance);

    // This should pass.
    Debug.Assert((int)field.GetValue(pen) == 5);

    // Create the pen without using constructor. 
    // No matter what, nothing is initialized meaning _ink is 0 and not 1000.
    // Hence, uninitialized.
    var uninitializedPen = (Pen)FormatterServices.GetUninitializedObject(typeof(Pen));
    field = uninitializedPen.GetType().GetField("_ink", BindingFlags.NonPublic|BindingFlags.Instance);

    //This will fail.
    Debug.Assert((int)field.GetValue(uninitializedPen) == 1000);
}

为了使用FormatterServices类,你需要导入System.Runtime.Serialization命名空间。

【讨论】:

  • @JonJin 您在问题中提供的原始代码?就我所见,这并没有什么问题。编辑:天哪.....
  • 我创建了一个实例,但是当我尝试获取值时,我得到了“NullReference”异常
  • @JonJin 查看您的链接代码粘贴,这是因为您从未提供构造函数参数。它无法为您创建 Pen,因为没有匹配的构造函数。
  • 谢谢你,我尝试的主要内容。我希望我能得到这 1000 个。
  • 这是一个教育任务,好像不完全正确
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-08
  • 1970-01-01
  • 2020-12-03
  • 1970-01-01
  • 2018-09-03
相关资源
最近更新 更多