【问题标题】:Mocking a private field模拟私有字段
【发布时间】:2012-06-28 03:18:48
【问题描述】:

我知道有人问过类似的问题,但我没有找到明确的解决方案。我试图从一个大班模拟一个私人领域。私有字段在一些较早的方法中被实例化,我正在尝试对引用该字段的后一种方法进行单元测试。

所以我在课堂上有一个较早的方法:

public bool validateAll(ref DataEntry[] oEntries, string sMediaPlanId, ITemplateGenerator oTempGen)
{
  ...
  // private field that I am trying to mock
  this._sMediaPlanObjective = (MPWrapper.Instance).getMediaPlanObjective(sMediaPlanId);
  ...
}

我正在尝试对引用私有字段的方法进行单元测试:

public bool validateFlightObjective(ref MPDataEntry oEntry)
{
  ...
  string entryFlightObjective = oEntry.getFlightObjective();
  string mediaPlanObjective = this._sMediaPlanObjective;

  if (entryFlightObjective != mediaPlanObjective)
  {
    return false;
  }
  ...

  return true;      
}

鉴于我的班级很大,而这只是我想测试的一种方法,有没有可能的方法来模拟这个私有字段?我错过了一些基本的东西还是应该考虑其他方法?

【问题讨论】:

  • 如答案中所述,您可以(应该)通过一些重构工作来避免这种情况。如果您仍然不想这样做,您可以尝试更强大的模拟框架,例如 Typemock Isolator 或 Moles。

标签: c# unit-testing moq rhino-mocks nmock


【解决方案1】:

您不能模拟任何私有的、静态的或本质上不可覆盖的任何东西(这是一个免费的模拟库 limitation)。

在这种情况下,您通常会做的事情(当 private 成员 必须 进行测试时)是将您的 private 成员提取到单独的类中并将 inject 提取到测试类作为依赖项。

在您的情况下,您实际上需要提取创建_sMediaPlanObjective 的代码,即这一行:

this._sMediaPlanObjective =
    (MPWrapper.Instance).getMediaPlanObjective(sMediaPlanId);

提供getMediaPlanObjective 方法的对象应该被注入到你的测试类中。如果这样做,您可以简单地模拟该对象并告诉它返回 _sMediaPlanObjective 的模拟版本。

【讨论】:

  • 这是否意味着必须调用 validateAll() 来设置私有成员的模拟版本,以便我可以测试 validateFlightObjective()?还是让一些公共/受保护的访问器来设置私有成员会更好。
  • @SamuelHeaney:很可能是这样。如果在validateAll 方法中仅 完成对私有字段的分配(并且不能在其他地方完成,例如在注入依赖项后在构造函数中完成),则需要调用它来设置模拟。仅出于单元测试的目的添加额外的访问器应该是最后的手段。
【解决方案2】:

没有理由对private 字段进行任何类型的测试。

使用一个对象,您可以引用public 方法作为对象API。 对象本身可以根据您对其执行的操作来改变状态 - 但它将反映在其他 public 方法/对 DAL 的访问(数据库/注册表/文件/任何其他不在内存中的资源)中

因此,在您的情况下,您可以进行这样的单元测试:

按照您的预期调用初始化私有字段的方法,然后 -

  • 用你知道的参数调用validateFlightObjective,根据_sMediaPlanObjective“想要成为状态”返回false,并验证结果是否为false。

  • 调用validateFlightObjective,使用你知道根据_sMediaPlanObjective“想要成为状态”返回true的参数,并验证结果是否为true。

如果您发现很难测试这个对象,那么这可能是一种“异味”——也许您在那里有不止一个责任,您应该开始重构并将类拆分为更容易测试的更小的类

有点长,希望对你有帮助

【讨论】:

  • 我不想测试私有字段本身。调用初始化私有字段的方法不会违反单元测试中的行为隔离吗?此外,调用它意味着调用其他几个需要按顺序调用并访问数据库的方法。
【解决方案3】:

您可以使用 JustMock 框架。 例如:

double value = 0;
var fakeFilterSetHelper = Mock.Create<FilterSetHelper>(Behavior.CallOriginal);
Mock.NonPublic.Arrange<double>(fakeFilterSetHelper, memberName: "GetPriceRangeFromSession").Returns(value);

【讨论】:

    猜你喜欢
    • 2010-10-09
    • 1970-01-01
    • 2013-07-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多