【问题标题】:How to create type safety on a PrivateObject in C#如何在 C# 中的 PrivateObject 上创建类型安全
【发布时间】:2018-03-07 17:31:58
【问题描述】:

我发现了一种对私有方法进行单元测试的绝妙方法。

这很好,只是我不喜欢将方法名称作为字符串输入。有没有办法建立一个“安全网”?我想键入方法名称,以便在对象上不存在该方法时编译器可以抛出编译器时错误。

私有方法:

public class BankAccount
{
    //Private method to test
    private bool VerifyAmount(double amount)
    {
        return (amount <= 1000);
    }
}

单元测试:

[TestMethod()]        
public void VerifyAmountTest()
{
    //Using PrivateObject class
    PrivateObject privateHelperObject = new PrivateObject(typeof(BankAccount));                             
    double amount = 500F;
    bool expected = true;
    bool actual;
    actual = (bool)privateHelperObject.Invoke("VerifyAmount", amount);            
    Assert.AreEqual(expected, actual);            
}

我知道有些人认为我们不应该对私有方法进行单元测试。这不是这个问题的目的,所以我们不要讨论这个问题并继续讨论这个问题。

【问题讨论】:

  • 你认为你不应该测试私有方法吗?

标签: c# unit-testing type-safety privateobject.invoke


【解决方案1】:

当您对一个类进行单元测试时,您实际上是在戴上您的消费者帽子并调用该类的 公开 方法来验证该类是否按照它声称的那样做做。

例如,考虑使用您的 BankAccount 类的示例:

public class BankAccount
 {
     public Widthdrawal WithdrawMoney(double amount)
     {
          if(!VerifyAmount(amount))
               throw new InvalidOperationException("Minimum dispensed is $1,000!");
          //Do some stuff here
          return new Withdrawal(1000);
     }
     private bool VerifyAmount(double amount)
     {
         return (amount <= 1000);
     }

 }

然后您可以测试一些东西。例如:

  1. 有效金额会导致提款。
  2. 无效金额导致无效操作异常。

你的测试:

[TestMethod]
public void Verify_Valid_Amount_Results_In_Widtdrawal()
{
     var bankAccount = new BankAccount();
     var withdrawal = bankAccount.WithdrawMoney(1200);
     Assert.IsNotNull(withdrawal);
     Assert.AreEqual(1200, withdrawal);
}


[TestMethod]
[ExpectedException(typeof(InvalidOperationException))]
public void Verify_Valid_Amount_Results_In_Exception()
{
     var bankAccount = new BankAccount();
     var withdrawal = bankAccount.WithdrawMoney(800);
}

如您所见,您测试的是使用私有方法的功能,而不是私有方法本身。

如果验证该方法对您很重要,您可以将其公开或将数量验证的概念抽象到另一个公开该方法并且可以单独进行单元测试的类。

【讨论】:

  • 关于我们应该对什么进行单元测试有很多不同的观点。你没有回答我的问题。你跑题了。
  • 认为单元测试 == 测试类的公共接口是一种常见的误解。顾名思义,它是“对unit 的测试”,其中unitunit of funcionality。测试私有/内部方法是完全合法的。在 C# 或 Java 等某些语言中,这更困难(您必须使用反射和硬编码字符串,这既棘手又无聊),在其他语言(Python)中,您根本没有私有方法,您认为所有方法都是“私有的”带有下划线,但这只是一个约定,您可以像公共的一样访问和测试它们。
  • @MassimilianoKraus:我们不要把它变成一场哲学战争。这将是我最后的评论。如果您想测试方法本身,您可以随时将其公开或将金额验证的概念抽象到另一个类,然后您可以将其传递给原始对象。这样您就可以单独验证金额逻辑。您可能会将 Python 缺乏访问控制视为一项功能。我认为这是一个小姐。总之,各有各的。 :-)
  • @Juan:“哲学”?这些想法会影响您编写代码的方式以及编写测试的方式。这是您设计应用程序的方式。这是一场非常实际的战争。战争?不,这不是一场战争,这是一个简单的讨论,我们都在这里互相学习和倾听:-)
  • 我完全愿意讨论@MassimilianoKraus,但这不是地方。 :-)
【解决方案2】:

您想检查 .Net 对象上是否存在 private 方法是否正确?

然后选择以下情况之一从实例中提取任何方法:

案例1如果你不关心方法签名:

var typeOfObj = typeof(BancAccount)
               .GetMethods(
                 BindingFlags.NonPublic | 
                 BindingFlags.Instance)
               .Any( method => method.Name == testedName )

案例 2 如果您需要指定确切的签名,请使用 - typeof(BancAccount).GetMethod(testedName, &lt;types of arguments&gt;)

【讨论】:

  • 不,他们的问题是“如何在不使用字符串的情况下引用私有财产”
  • 不。他想测试私有方法,现在他正在使用反射来命名。
  • 在这种情况下,“testedName”不就是代表方法名的字符串吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-08-19
  • 2014-02-23
  • 2017-08-03
  • 2020-07-10
  • 2017-06-17
  • 2018-11-22
  • 2020-02-27
相关资源
最近更新 更多