【问题标题】:Automatic way of generating accessor classes in C#在 C# 中自动生成访问器类的方法
【发布时间】:2012-12-24 21:07:17
【问题描述】:

我遇到了以下问题。假设有一个类,其中包含一个必须测试的私有类。要切断不必要的 cmets 和答案,是它必须保持私密,是,它必须经过测试。

说,它看起来像这样:

public class PublicClass
{
    private class InternalClass
    {
        void Method() { }
    }
}

为了方便测试,我想创建以下类:

public class InternalClassAccess
{
    private object instance;

    public InternalClassAccess()
    {
        // Use reflections to instantiate InternalClass
        // and store it in instance field
    }

    public void Method()
    {
        // Use reflections to call Method() on
        // stored instance
    }
}

我可以手动编写这样的类,但我想知道,是否有某种自动方式这样做?我有专业版的 VS 2012。

【问题讨论】:

  • "是的,它必须保持私密" -- 如果它必须保持私密,但也必须在 PublicClass 之外访问,那么您的设计有问题。你没有解释为什么它必须是private,我无法想象为什么它会是一个问题internal。
  • 加上如果是internal,你可以加[InternalsVisibleTo(...)]并指定你的测试项目;那么你的测试项目就可以访问了。
  • 它应该不在PublicClass之外就项目而言是可访问的。另一方面,我想测试它,所以我必须访问这个类(或其他私人成员)。想象一个巨大的类,它有一个方法 DoSomethingComplicatedAndExtremelySpecific 和 100 个小的私有方法,它们做的事情甚至更具体(所以它们不应该可见,也不应该被提取),但是什么会影响最终结果(所以应该对它们进行测试)。我明确写了 not 以切断有关方法隐私和测试需要的 cmets。请接受这些事实。
  • @Spook:这听起来像是无论如何都可以重构的东西。哎呀,听起来它可能是一个完全独立的程序集,只有一个公共类和大量内部类 - 然后您可以使用 InternalsVisibleTo 进行测试。
  • 想象一下 JPeg 类,它允许您将原始字节 [] 压缩并保存为 Jpeg 文件。该类属于具有类似类的更大程序集:Png、Tiff 等。该类导出两个公共方法:Save 和 Load,但包含一些私有方法,它们实际上可以完成工作。它们不应该是内部的,因为尽管这个类没有人使用它们。你会测试这些吗?

标签: c# unit-testing class private


【解决方案1】:

我不知道 .NET 中为此内置了什么 - 但您可以使用dynamic 为所有此类类编写您的类一次。你会有这样的结构:

public class PrivateDynamicAccessor : DynamicObject
{
    private readonly object instance;

    public PrivateDynamicAccessor(string typeName)
    {
        // Instantiate here via reflection
    }

    public override bool TryGetMember(GetMemberBinder binder,
                                      out Object result)
    {
        // Access the fields or properties with reflection
    }
}

(同样TryInvokeMember 用于方法等)

那么你可以把它当作:

dynamic foo = new PrivateDynamicAccessor("Foo.Bar+Baz");
string name = foo.Name;
// etc

(我同意不得不这样做很奇怪的评论,请注意。你真的不能让它内部化吗?)

【讨论】:

  • You really can't make it internal? - 将此类设为内部而不是私有,就像修改汽车的串行车身,以便可以在内部安装碰撞凸轮。你不觉得修改程序架构以适应单元测试是错误的吗?
  • @Spook:不是真的——你不能对它进行单元测试的事实是代码的味道。 IMO,您拥有“具有一个方法 DoSomethingComplicatedAndExtremelySpecific 和 100 多个小型私有方法的大型类”这一事实是代码异味。对我来说,这听起来不够专注。
  • 我会在这里回答,“一个尺寸不适合所有人”。目前我正在执行相当复杂的图像分析,我的类是一个黑盒子——它接收图像并返回从中提取的一些数据。然而这个过程是非常具体和相当复杂的,所以确实有很多私有的 specific 方法,不应该暴露,而应该被测试。假设一下,这些方法作为项目的架构要求是私有的——你会测试它们吗?还是通过内部化来向更多受众展示?
  • 想象一下汽车发动机——这是一项巨大的技术,但它的“公共界面”只是:转动钥匙,它开始旋转;踩下油门踏板,它转得更快。它的所有部分都隐藏在内部(私有)。我正在谈论的类非常相似,但我认为,还有更多的情况是判断通过将许多方法设为私有来隐藏许多方法的决定。
  • 汽车零件可能“隐藏”在汽车中,但许多零件是可替换的、具有公共接口的自主对象。
【解决方案2】:

你可以使用一些预处理指令:

public class PublicClass
{
    #if DEBUG
    public class InternalClass
    #else
    private class InternalClass
    #endif
    {
        void Method() { }
    }
}

//Only valid when testing in Debug
public class TestableInternalClass : PublicClass.InternalClass
{

}

【讨论】:

  • 尽管我讨厌使用宏和编译器指令,但这实际上是个好主意,因为它使封装在项目级别(例如,您可能有仅用于测试的特殊指令)。不过,我认为这是最后的手段。
【解决方案3】:

在 Visual Studio 2010 Ultimate 中,您只需右键单击方法/构造函数并选择生成测试。这将为外部类创建一个访问器类,允许您访问私有内部类。

【讨论】:

  • 不幸的是,我在上下文菜单中没有这样的选项。你有哪个版本的 Visual Studio?
  • 我在 Visual Studio 2010 Ultimate 中对此进行了测试。
  • 不幸的是,我有专业版的VS;我想,此功能仅在 Test Suite 和 Ultimate 版本中可用...
猜你喜欢
  • 2012-09-16
  • 2011-11-18
  • 1970-01-01
  • 2012-03-02
  • 2012-05-04
  • 2011-10-23
  • 1970-01-01
  • 2014-09-09
  • 1970-01-01
相关资源
最近更新 更多