我以前问过一个关于如何set value of interface in testing a method的问题。我已经成功地在我的项目中实现了Moq框架,并且测试运行良好。
这是我提供的示例代码:
public void PostEvent(
eVtCompId inSenderComponentId,
eVtEvtId inEventId,
long inEventReference,
IF_SerializableData inEventData)
{
if(mEventMap.ContainsKey(inEventId))
{
mEventMap[inEventId](inSenderComponentId, inEventReference, inEventData);
}
}这里我有4个参数:1:枚举,2:另一参数,3:长,4:接口。--然而,,我错了,因为第四个参数(接口)不应该是接口,而是接口的reference。
所以应该是这样的:
public void PostEvent(
eVtCompId inSenderComponentId,
eVtEvtId inEventId,
long inEventReference,
ref IF_SerializableData inEventData)给我的Moq测试代码样本(就是这个).
var serializable = new Mock<IF_SerializableData>();
target.PostEvent(..., serializable.Object);.行不通我尝试过ref serializable.Object,但是它仍然不能工作,因为我得到了一个错误,即ref参数期望一个变量的引用,而不是一个对象。
关于如何正确地测试这一点,有什么建议或例子吗?
发布于 2012-12-11 08:53:12
您需要将Object引用从serializable模拟复制到一个局部变量中,这样就可以将它作为ref传递。
IF_SerializableData localRef = serializable.Object;
target.PostEvent(..., ref localRef);您不能传递ref Serializable.Object,因为它是一个属性--参见Is it possible to pass properties as "out" or "ref" parameters?,它提供了关于为什么会出现这种情况的极好的讨论,以及其他链接的来源。
我的解释
这最终是因为属性不是变量。读/写属性是一对get和set访问器方法,它们提供类似变量的功能,但关键的是,当您对属性进行get时,您总是得到底层变量的副本--即使该变量具有引用类型。
所以:
public class MyClass {
private object _property;
public object Property {
get { return _property; } //<-- _property reference copied on to stack & returned
// here as a new variable. Therefore a ref
// on that is effectively meaningless.
// for a ref to be possible you'd need a pointer
// to the _property variable (in C++ terms)
set { _property = value; }
}
}在本例中--如果您可以将ref MyClass.Property传递给一个方法--它将毫无意义,因为它将传递对堆栈中一个瞬态变量的引用--即Property get accessor; it would not be passing the property by reference. So C# doesn't allow it, even though it could, because it would imply thatProperty`‘返回的引用的副本可以由该方法修改--而它根本不能。
因此,在您的情况下,我们需要从堆栈中捕获该值并将其复制到局部变量中。现在-注意,为了使ref方法设置的新值出现在Mock<T>上,您需要再次将它的Object属性设置为局部变量值(如果可以的话--我不使用Moq,但假设它是不可变的)。
对于C#是否应该以这种方式自动处理ref Property (请参阅前面提到的,所以我链接到),已经有了很多争论。在我看来,这类似于ref Derived与ref Base不兼容-是的,有一种方法可以自动地为您处理这个问题,但是它应该吗?在我看来,没有。我会因此而受挫吗?是的,当然--但我经常发现它突出了真正应该修复的体系结构缺陷(例如,依赖返回值可能更好的ref或out参数)。
C#允许您通过引用传递属性的唯一方法是将get和set访问器传递到目标方法--这与ref完全不兼容(因为这只是一个内存位置)。
作为体验者,您必须编写这样的方法,如下所示:
public static void MyUglyRefMethod(Func<object> refGet, Action<object> refSet)
{
var read = refGet();
var newValue = new object();
refSet(newValue);
}有了这个,我们现在可以在MyClass上提供类似于MyClass的语义
MyClass a = new MyClass();
MyUglyRefMethod(() => a.Property, (newValue) => a.Property = newValue);
Assert.IsNotNull(a.Property);但这简直太丑了。
创建一个获取ref MyClass的方法比较简单,然后它可以直接写入任何属性。
https://stackoverflow.com/questions/13816305
复制相似问题