假设我有一堆看起来像......的课程。
class Foo{
private Bar highlyCoupled = new highlyCoupled();
public bool DoTheThing(){
return highlyCoupled.doesTheThing();
}
}
是否有可能使用反射打开foo和注入(duck-punch可能是一个更正确的术语)某种mockHighlyCoupled代替highCoupled?
在这种情况下怎么样......
class DoubleFoo : Foo{
public bool DoTheOtherThing(){
return DoTheThing();
}
}
继承的highCoupled可以在其中插入模拟吗?
不幸的是,重构代码以便不需要反射。
答案 0 :(得分:1)
您确实可以使用反射和模拟类型,但该类型必须从原始类型继承(否则FieldInfo.SetValue将失败)。
void Main()
{
var bar = new Bar();
var type = typeof(Bar);
// Get the type and fields of FieldInfoClass.
var fields = type.GetFields(BindingFlags.NonPublic | BindingFlags.Instance);
fields[0].SetValue(bar, new FooMock()); // you can use new Foo() here too.
bar.Print();
}
class Foo {
public int i = 0;
}
class FooMock : Foo {
}
class Bar {
private Foo foo = new Foo();
public void Print() {
Console.WriteLine(i);
}
}
答案 1 :(得分:1)
由于您无法使用模拟框架进行重构,因此可以使您更轻松。例如:
TypeMock:
var fakeType = Isolate.Fake.Instance<SomeType>();
ObjectState.SetField(fakeType, "_somePrivateField", myValue);
起订量:
var fakeType = new Mock<SomeType>()
fakeType.Protected().Setup<SomeType>("_somePrivateField").Returns(myValue);
老实说,我并没有真正尝试过Moq,但我认为它会做你需要的。
答案 2 :(得分:0)
如果你根本无法重构(使highlyCoupled
受保护),那么你就会陷入使用反射的境地。这样您就可以在不修改的情况下设置highlyCoupled
的值。
答案 3 :(得分:0)
我普遍同意罗布;如果你不能重构这个以使依赖关系更松散地耦合(至少允许派生类像测试代理一样覆盖它的默认值),那么尽管它的可见性设置值的反射几乎是唯一的你可以去的方式。
您可以做的绝对最少的是保护依赖项。如果现在或将来的任何时候都可以做到这一点,那就去做吧:
class Foo{
protected Bar highlyCoupled = new highlyCoupled();
public bool DoTheThing(){
return highlyCoupled.doesTheThing();
}
}
...
//in your test suite
class FooTestProxy:Foo
{
public FooTestProxy(Bar testMock)
{
highlyCoupled = testMock;
}
}
//now when testing, instantiate your test proxy and pass it the mocked object