1

假设我有一堆看起来像......

class Foo{
  private Bar highlyCoupled = new highlyCoupled();

  public bool DoTheThing(){
    return highlyCoupled.doesTheThing();
  } 
}

是否可以使用反射来打开 foo 并注入(duck-punch 可能是一个更正确的术语)某种 mockHighlyCoupled 来代替 highlyCoupled?

这种情况下怎么办...

class DoubleFoo : Foo{
  public bool DoTheOtherThing(){
    return DoTheThing();
  }
}

继承的highlyCoupled 可以在其位置插入一个模拟吗?

不幸的是,重构代码以便不需要反射是不可能的。

4

4 回答 4

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);
    }
}
于 2012-04-05T14:39:23.210 回答
1

由于您无法使用模拟框架进行重构,因此这对您来说会更容易一些。例如:

类型模拟:

var fakeType = Isolate.Fake.Instance<SomeType>();
ObjectState.SetField(fakeType, "_somePrivateField", myValue);

起订量:

var fakeType = new Mock<SomeType>()
fakeType.Protected().Setup<SomeType>("_somePrivateField").Returns(myValue);

老实说,我实际上并没有在 Moq 上尝试过这个,但我认为它会满足你的需要。

于 2012-04-05T15:26:58.353 回答
0

如果您根本无法重构(使highlyCoupled受保护),那么您将无法使用反射。这将使您highlyCoupled无需修改​​即可设置 的值。

于 2012-04-05T14:27:45.953 回答
0

我大体上同意 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
于 2012-04-05T14:35:47.783 回答