如何在 C# 中的 PrivateObject 上创建类型安全
How to create type safety on a PrivateObject in C#
我发现了一种对私有方法进行单元测试的绝妙方法。
这很棒,只是我不喜欢将方法名称输入为字符串的方式。有没有办法创建一个 "safety net?" 我想键入方法名称,以便如果对象上不存在该方法,编译器可以抛出编译时错误。
私有方法:
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);
}
我知道有些人认为我们不应该对私有方法进行单元测试。这不是这个问题的目的,所以我们不要讨论这个问题并留在主题上。
您想要检查 .Net 对象上是否存在 private
方法,我说得对吗?
然后选择以下情况之一从实例中提取任何方法:
案例1如果你不关心方法签名:
var typeOfObj = typeof(BancAccount)
.GetMethods(
BindingFlags.NonPublic |
BindingFlags.Instance)
.Any( method => method.Name == testedName )
案例 2 如果您需要指定确切的签名,请使用 - typeof(BancAccount).GetMethod(testedName, <types of arguments>)
当您对 class 进行单元测试时,您实际上是在戴上消费者帽子并调用 exposed 方法class 来验证 class 是否如其所言。
例如,考虑使用您的 BankAccount
class:
public class BankAccount
{
public Widthdrawal WithdrawMoney(double amount)
{
if(!VerifyAmount(amount))
throw new InvalidOperationException("Minimum dispensed is ,000!");
//Do some stuff here
return new Withdrawal(1000);
}
private bool VerifyAmount(double amount)
{
return (amount <= 1000);
}
}
然后您可以测试一些东西。例如:
- 有效金额导致提款。
- 无效金额导致无效操作异常。
您的测试:
[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);
}
如您所见,您测试的是使用私有方法的功能,而不是私有方法本身。
如果验证该方法对您来说很重要,您可以将它 public 或将金额验证的概念抽象为另一个 class 公开此方法并可以单独进行单元测试。
我发现了一种对私有方法进行单元测试的绝妙方法。
这很棒,只是我不喜欢将方法名称输入为字符串的方式。有没有办法创建一个 "safety net?" 我想键入方法名称,以便如果对象上不存在该方法,编译器可以抛出编译时错误。
私有方法:
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);
}
我知道有些人认为我们不应该对私有方法进行单元测试。这不是这个问题的目的,所以我们不要讨论这个问题并留在主题上。
您想要检查 .Net 对象上是否存在 private
方法,我说得对吗?
然后选择以下情况之一从实例中提取任何方法:
案例1如果你不关心方法签名:
var typeOfObj = typeof(BancAccount)
.GetMethods(
BindingFlags.NonPublic |
BindingFlags.Instance)
.Any( method => method.Name == testedName )
案例 2 如果您需要指定确切的签名,请使用 - typeof(BancAccount).GetMethod(testedName, <types of arguments>)
当您对 class 进行单元测试时,您实际上是在戴上消费者帽子并调用 exposed 方法class 来验证 class 是否如其所言。
例如,考虑使用您的 BankAccount
class:
public class BankAccount
{
public Widthdrawal WithdrawMoney(double amount)
{
if(!VerifyAmount(amount))
throw new InvalidOperationException("Minimum dispensed is ,000!");
//Do some stuff here
return new Withdrawal(1000);
}
private bool VerifyAmount(double amount)
{
return (amount <= 1000);
}
}
然后您可以测试一些东西。例如:
- 有效金额导致提款。
- 无效金额导致无效操作异常。
您的测试:
[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);
}
如您所见,您测试的是使用私有方法的功能,而不是私有方法本身。
如果验证该方法对您来说很重要,您可以将它 public 或将金额验证的概念抽象为另一个 class 公开此方法并可以单独进行单元测试。