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

考虑以下课程

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的unit testing中触发SomeMethod 。 如何重写我的代码,以便我仍然可以在同一个程序集中使用internal方法,但只将公共成员公开给其他程序集?

更新:OtherClass是一个实用程序类,需要在Entity类的内部操作,而不是直接向用户公开。 但是,此类本身向用户公开,因此它们间接访问Entity内部。 这是期望的,因为SomeMethod将执行必要的检查以确保用户不会搞砸Entity对象的内部状态。

编辑:

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

 public interface IEntity { //Implementation } internal interface ITestEntity : IEntity { void TestMethod(); } class Entity: ITestEntity { // } 

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

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

 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 : CI { private interface I {} } 

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

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

对于一般的unit testing,如果您不测试私有或内部方法,它总是一个好的模式。 unit testing实际上应该只测试公共接口,任何业务类都应该提供在内部执行任何操作的公共方法…因此,要测试内部方法,您必须测试它的公共表示。

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

在此处查找有关这些生成类型的更多信息: 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().Setup(p => p.GetSomething()).Returns(null); }