如何创建一个接口,使一些方法保持在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
或通过转换到接口,因为Bar
和ITest
都是内部的。
我注意到基类必须至少与其派生类一样可见。 不是那么接口。 很少有人知道这是合法的:
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); }