如何创建一个接口,使一些方法保持在C#中进行测试?

时间:2013-09-22 12:50:35

标签: c# unit-testing interface internal

考虑以下课程

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对象的内部状态。

3 个答案:

答案 0 :(得分:13)

  

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

将界面设为内部,然后明确实现。

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 {} 
}

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

答案 1 :(得分:4)

编辑:

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

public interface IEntity
{
    //Implementation

}

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


class Entity: ITestEntity
{
   //
}

答案 2 :(得分:2)

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

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

但无论如何。如果要测试私有或内部访问器,Visual Studio Test项目通常可以为您生成访问器包装器。 你必须打电话给访问者ctor而不是你班级的正常人。执行此操作时,您可以访问该实例的任何私有或内部方法/属性。

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

:编辑:经过讨论,我有一个示例,介绍如何将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);
}