9

考虑下面的类

public class Entity {
  public void Foo() { ... }
  internal void Bar() { ... }
}

如您所见,它有一个public方法和一个internal方法。现在,我想创建一个接口,允许我在测试中模拟这个类(在这个程序集中和其他程序集中)。我重写我的代码如下:

public interface IEntity {
  void Foo();
}

internal class Entity : IEntity {
  public void Foo() { ... }
  public void Bar() { ... }
}

但是,这会产生另一个问题。当在同一个程序集中的另一个方法中使用该类时,我不能再调用Bar了:

public class OtherClass {
  public void SomeMethod(IEntity entity) {
    entity.Bar(); // error!
  }
}

像这样重写代码:

public class OtherClass {
  public void SomeMethod(IEntity entity) {
    (entity as Entity).Bar(); // error in test!
  }
}

将在触发的单元测试中触发错误SomeMethod。如何重写我的代码,以便我仍然可以internal在同一个程序集中使用方法,但只将公共成员公开给其他程序集?

更新:OtherClass是一个实用类,需要对Entity类的内部进行操作,这些内部不直接暴露给用户。然而,这个类本身是暴露给用户的,所以他们间接地可以访问Entity. 这是需要的,因为SomeMethod将执行必要的检查以确保用户不会搞砸Entity对象的内部状态。

4

3 回答 3

15

如何重写我的代码,以便我仍然可以在同一个程序集中使用内部方法,但只将公共成员公开给其他程序集?

使接口成为内部接口,然后显式实现它。

internal interface ITest
{
  void Foo();
  void Bar();
}

public class Thing : ITest
{
  void ITest.Foo() { this.Foo(); }
  void ITest.Bar() { this.Bar(); }
  public Foo() { ... }
  internal Bar() { ... }
}

所以现在公共类Thing只有一个公共方法Foo。程序集外部的代码既不能Bar直接调用,也不能通过转换为接口调用,因为BarITest都是内部的。

我注意到基类必须至少与其派生类一样可见。不是这样的接口。很少有人知道这是合法的:

class C : C.I
{
    private interface I {} 
}

一个类可以实现一个只有它才能看到的接口!这有点奇怪,但在某些情况下它是有意义的。

于 2013-09-22T13:31:09.603 回答
5

编辑:

IEntity使用内部接口扩展您的接口以ITestEntity进行测试:

public interface IEntity
{
    //Implementation

}

internal interface ITestEntity : IEntity
{
    void TestMethod();
}


class Entity: ITestEntity
{
   //
}
于 2013-09-22T13:28:32.200 回答
2

我假设您只想在单元测试中调用内部方法,对吗?因为否则,将方法暴露给其他程序集将需要将 internal 替换为 public of cause。

对于一般的单元测试,如果您不测试私有或内部方法,它总是一个很好的模式。单元测试实际上应该只测试公共接口,任何业务类都应该提供在内部做任何事情的公共方法......所以要测试你的内部方法,你必须测试它的公共表示。

但无论如何。如果您想测试私有或内部访问器,Visual Studio 测试项目通常可以为您生成访问器包装器。您将不得不调用访问器 ctor 而不是类的普通 ctor。当您这样做时,您可以访问该实例的任何私有或内部方法/属性。

在此处查找有关这些生成类型的更多信息:http: //msdn.microsoft.com/en-us/library/bb385974 (v=vs.100).aspx

:edit: 经过讨论,我为您提供了一个示例,说明如何将 moq 与 Unity 和 UnityAutoMoq(3 个不同的 Nugets)一起使用。假设您的课程如下所示:

public class MyClassWithInternalMethod
{
    internal object GetSomething()
    {
        return null;
    }
}

要对此进行测试,您可以像这样模拟它:

using (var moqUnityContainer = new UnityAutoMoqContainer())
{
    moqUnityContainer.GetMock<MyClassWithInternalMethod>().Setup(p => p.GetSomething()).Returns(null);
}
于 2013-09-22T13:19:16.480 回答