在.net中对高度耦合的代码进行单元测试;反射以注入mock
本文关键字:单元测试 反射 mock 注入 代码 net 高度 耦合 | 更新日期: 2023-09-27 18:30:03
假设我有一堆类,看起来像。。。
class Foo{
private Bar highlyCoupled = new highlyCoupled();
public bool DoTheThing(){
return highlyCoupled.doesTheThing();
}
}
是否可以使用反射打开foo并在highlyCoupled的位置注入某种mockHighlyCouple(duck-panch可能是一个更正确的术语)?
在这种情况下。。。
class DoubleFoo : Foo{
public bool DoTheOtherThing(){
return DoTheThing();
}
}
继承的highlyCoupled可以在它的位置插入一个mock吗?
不幸的是,重构代码以不需要反射是不可能的。
因为您不能使用mocking框架进行重构,所以这对您来说会更容易一些。例如:
TypeMock:
var fakeType = Isolate.Fake.Instance<SomeType>();
ObjectState.SetField(fakeType, "_somePrivateField", myValue);
Moq:
var fakeType = new Mock<SomeType>()
fakeType.Protected().Setup<SomeType>("_somePrivateField").Returns(myValue);
老实说,我还没有和莫一起尝试过,但我认为它会满足你的需要。
您确实可以使用反射和模拟类型,但该类型必须从原始类型继承(否则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);
}
}
如果你根本不能重构(使highlyCoupled
受到保护),那么你就只能使用反射了。这将允许您在不进行修改的情况下设置highlyCoupled
的值。
我大体上同意Rob的观点;如果你不能重构它以使依赖关系更松散地耦合(至少允许像测试代理这样的派生类覆盖其默认值),那么反射来设置值(尽管它是可见的)几乎是你唯一可以走的路。
你能做的最起码的事情就是保护依赖关系。如果这在现在或未来的任何时候都是可能的,那么就去做:
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