Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/339.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# PrivateObject不会返回参数_C#_Unit Testing - Fatal编程技术网

C# PrivateObject不会返回参数

C# PrivateObject不会返回参数,c#,unit-testing,C#,Unit Testing,我试图在单元测试项目中测试私有方法。到目前为止,一切都很顺利,但当我不得不用out参数测试一个方法时,我遇到了麻烦。该方法的签名为: private bool GotSSI(out SSI ssi, RSI rsi) { ~code omitted~ } 单元测试(不工作的部分)如下所示: SSI ssi = null; object[] p = new object[]{ssi,rsi}; Type[] t = new Type[] { typeof(SSI).MakeByR

我试图在单元测试项目中测试私有方法。到目前为止,一切都很顺利,但当我不得不用out参数测试一个方法时,我遇到了麻烦。该方法的签名为:

private bool GotSSI(out SSI ssi, RSI rsi)
{
        ~code omitted~
}
单元测试(不工作的部分)如下所示:

SSI ssi = null;
object[] p = new object[]{ssi,rsi};
Type[] t = new Type[] { typeof(SSI).MakeByRefType(), typeof(RSI) };
actual = (bool) privateTarget.Invoke("GotSSI",t,p);
GotSSI方法有效。我已经在单元测试的调试模式下对它进行了测试,我可以看到在返回其真值或假值之前,在方法内部设置了'ssi'out变量。但是当测试返回到自己的代码时,“ssi”变量仍然为null。所以问题是我在“GotSSI”方法中创建的对象没有从PrivateObject调用方法中解析出来

有人知道我错过了什么吗

更新(Rafal提供的解决方案)

Rafal的解决方案非常有效,下面是我如何实施该解决方案的

我创建了一个委托:

delegate bool GotSSIInternal(out SSI ssi, RSI rsi);
actual = gotSSIInternal.Invoke(out ssi, rsi);
当我创建了我想要测试的对象时,我构建了委托(目标是我正在测试的对象):

之后,调用委托非常简单:

delegate bool GotSSIInternal(out SSI ssi, RSI rsi);
actual = gotSSIInternal.Invoke(out ssi, rsi);

这个解决方案非常简单,工作起来很有魅力。

如果您想获得out值,那么使用out参数调用方法是错误的。请参阅如何通过反射调用它。

您需要问问自己是否真的需要测试私有方法?我个人不测试私人方法,但这完全取决于个人意见(而且可能会变得非常激烈)。有很多理由/文章/观点

从接受的答案中摘录的一段是“私有方法是应该对类的用户隐藏的实现细节。测试私有方法会破坏封装…”

我不测试私有方法的原因是它们比公共接口更容易更改。如果您涵盖了所有私有方法,那么重构会变得更加复杂(这也是我的观点)。如果您更改了一个私有方法,而公共接口中断,那么您将知道单元测试失败,然后可以向下钻取


这只是我的观点,我知道很多人不同意,所以就说出来吧

虽然最终被接受的解决方案是可行的,但有一种更简单的方法可以做到这一点。如果你按照Rafal的公认答案中给出的链接,你会发现一个与此类似的问题,有两个答案。第二个答案(最“有用”的点)是两个答案中比较简单的一个

以下是该答案的修改版本,专门针对测试场景:

//method to test is a private method of the class ClassTotest with signature 
//    TryGetCustomerData(List<Invoice> invoices, out CustomerData customerData) 
//set up
var objToTest = new ClassToTest();
var invoices = GetInvoices();
CustomerData customerData = null;

//set up the arguments
var args = new object[] { invoices, customerData };
//get the MethodInfo of the method you want to test
var method = typeof(ClassToTest).GetMethod("TryGetCustomerData",
    BindingFlags.NonPublic | BindingFlags.Instance);
//invoke it
var success = (bool)method.Invoke(objToTest, args);
//get back the customerData argument - the "out" parameter
var actual = args[1] as CustomerData;
//要测试的方法是带有签名的ClassTotest类的私有方法
//TryGetCustomerData(列出发票、out CustomerData CustomerData)
//设立
var objToTest=new ClassToTest();
var发票=GetInvoices();
CustomerData CustomerData=null;
//设置论点
var args=新对象[]{invoices,customerData};
//获取要测试的方法的MethodInfo
var method=typeof(ClassToTest).GetMethod(“TryGetCustomerData”,
BindingFlags.NonPublic | BindingFlags.Instance);
//调用它
var success=(bool)method.Invoke(objToTest,args);
//获取customerData参数“out”参数
var-actual=args[1]作为CustomerData;

我可以使用
PrivateObject
来执行此操作,尽管从技术上讲它不是一个“返回值”,例如:

实际上,如果可以在没有类型数组的情况下确定方法重载,则可以省略类型数组:

object[] p = new object[] { null, rsi };
actual = (bool)privateTarget.Invoke("GotSSI", p);
SSI ssi = p[0];

我知道对单元测试私有方法的普遍共识,通常我不会这么做。这里的问题是,我正在测试的这些方法从我可以使用的公共方法设置起来很复杂。使用私人测试更容易控制和理解。好奇谁/为什么投了反对票?您有权否决投票,但它有助于说明原因,否则它似乎毫无意义。为您定义一个帮助器类可能有意义:内部静态T MakeDelegate(string methodName,T target){return(T)Delegate.CreateDelegate(typeof(T),target,typeof(C).GetMethod(methodName,BindingFlags.NonPublic | BindingFlags.Instance));}但可能您已经想到了这一点。:-,不太可能。只有一次测试出现了这个问题,加上我时间紧迫。这是个不错的主意。我同意,这更简单。我试过了,它对我有效,谢谢!