考虑以下课程
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
对象的内部状态。
答案 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
或通过转换到界面,因为Bar
和ITest
都是内部的。
我注意到基类必须至少与其派生类一样可见。不是那么接口。很少有人知道这是合法的:
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);
}