我按以下方式设置了课程:
public abstract FooClass {
public FooClass() {
// init stuff;
}
public void RandomMethod() {
// do stuff;
}
public abstract WhatIWantToShim();
}
我想要做的是在ShimFooClass上设置WhatIWantToShim,如下所示:
ShimFooClass.AllInstances.WhatIWantToShim = () => Boo();
我可以设置RandomMethod就好了,
ShimFooClass.AllInstances.RandomMethod = () => CalculatePi();
但是,生成的ShimFooClass似乎不会在ShimFooClass的AllInstances属性上创建WhatIWantToShim属性。
我看过http://msdn.microsoft.com/en-us/library/hh549176.aspx#bkmk_shim_basics,但我没有看到任何有关抽象方法的内容。我看到的唯一不支持的是终结器。有人知道这里发生了什么,是否支持这种情况?
答案 0 :(得分:4)
唉唉....长号
接口和抽象方法。 Stubs提供了可用于测试的接口和抽象方法的实现。垫片不能检测接口和抽象方法,因为它们没有方法体。
http://msdn.microsoft.com/en-us/library/hh549175(v=vs.110).aspx
更新:虽然可以做什么是破坏垫片。
using (ShimsContext.Create())
{
bool wasAbstractMethodCalled = false;
var targetStub = new StubFooClass()
{
WhatIWantToShim01 = () => wasAbstractMethodCalled = true
};
var targetShim = new ShimFooClass(targetStub);
targetShim.AllInstances.RandomMethod = () => CalculatePi();
FooClass target = targetShim.Instance;
target.WhatIWantToShim();
Assert.IsTrue(wasAbstractMethodCalled, "The WhatIWantToShim method was not called.");
}
由于垫片无法处理绕过WhatIWantToShim方法和存根的方法,只需创建存根类的新实例并为抽象方法设置绕行处理程序。 (注意:在我的实际代码中生成伪造时,我自动添加了标记在WhatIWantToShim末尾的01)。
然后将实例化的存根传递给shim类的构造函数,并根据需要进行填充。
答案 1 :(得分:0)
我在这里回复是因为我很确定其他答案没有回答这个问题,以便将来的搜索会返回有用的信息。
首先,你不能使用shim接口。抽象方法相当于一个接口。此外,没有理由。
{
bool wasAbstractMethodCalled = false;
var targetStub = new StubFooClass()
{
WhatIWantToShim01 = () => wasAbstractMethodCalled = true
};
ShimFooClass.AllInstances.RandomMethod = @class => targetStub.CalculatePi();
targetStub.WhatIWantToShim();
Assert.IsTrue(wasAbstractMethodCalled, "The WhatIWantToShim method was not called.");
}
以上是上一个答案的简化版本,只会调用您刚刚分配的操作。这可能不是你的意图。
记住你为什么要垫片。当您想要避免在正在测试的方法中的方法调用的影响时,您可以进行填充。抽象方法没有主体,因此不会影响任何东西。唯一有用的时间是在儿童班,一开始就可以使用垫片。
您可能遇到问题的唯一情况是,第三个类是秘密持有抽象类的实例并使用子类实例化它。你无法假装。然而,这是一个糟糕的设计;实例应该来自某个方法(你可以填充)或传入(因为DI是一件好事!)或者抽象是没有价值的,你也可以将实例声明为子类型,因为你不以任何方式使用抽象。