gpt4 book ai didi

c# - 如何使现有的公共(public) API 可供使用它的外部程序员测试?

转载 作者:太空狗 更新时间:2023-10-29 21:31:46 25 4
gpt4 key购买 nike

我有一个 C# 公共(public) API,许多第三方开发人员都在使用它,这些开发人员在其上编写了自定义应用程序。此外,该 API 被内部开发人员广泛使用。

这个 API 的编写并没有考虑到可测试性:大多数类方法不是虚拟的,并且东西没有被分解到接口(interface)中。此外,还有一些辅助静态方法。

出于多种原因,我无法在不对使用我的 API 的程序员开发的应用程序造成重大更改的情况下对设计进行重大更改。但是,我仍然希望让使用此 API 的内部和外部开发人员有机会编写单元测试并能够模拟 API 中的对象。

有几种方法浮现在脑海中,但它们似乎都不是很好:

  • 传统的方法是强制开发人员创建一个他们控制的代理类来与我的 API 对话。这在实践中是行不通的,因为现在有数百个类,其中许多是有效的强类型数据传输对象,很难复制和维护。
  • 强制所有使用 API 的开发人员对其进行单元测试购买 TypeMock .这似乎很苛刻,迫使人们为每个开发人员支付 300 美元以上,并可能要求他们学习与过去不同的模拟对象工具。
  • 遍历整个项目并使所有方法虚拟化。这将允许使用像 Moq 这样的免费工具模拟对象。或 Rhino Mocks ,但它可能会为从未打算派生的类打开安全风险。此外,这可能会导致重大更改。
  • 我可以创建一个工具,给定一个输入程序集,它会输出一个具有相同命名空间、类和成员的程序集,但会使所有方法成为虚拟方法,并且它会使方法主体只返回返回类型的默认值。然后,我可以在每次发布 API 更新时发布这个虚拟测试程序集。然后,开发人员可以针对虚拟程序集编写 API 测试,因为它具有非常可模拟的虚拟成员。这可能有效,但为此编写自定义工具似乎有点乏味,而且我似乎无法找到一个做得好的现有工具(尤其是与泛型配合良好的工具)。此外,它的复杂性在于它需要开发人员使用可能会过时的两个不同的程序集。
  • 与#4 类似,我可以遍历每个文件并向每个方法和主体添加诸如“#ifdef UNITTEST”之类的内容,以执行与工具所做的等效的操作。这不需要外部工具,但它会用很多丑陋的“#ifdef”污染代码库。

  • 还有其他我认为不合适的东西吗?我在#4 中提到的工具是否已经存在?

    同样,复杂的因素是这是一个相当大的 API(数百个类和大约 10 个文件),并且有现有的应用程序在使用它,这使得很难进行剧烈的设计更改。

    那里 have been several questions在 Stack Overflow 上,关于改造现有应用程序以使其可测试是通用的,但似乎没有解决我所担心的问题(特别是在许多第三方开发人员广泛使用的 API 的上下文中)。我也知道“ Working Effectively With Legacy Code”并认为它有很好的建议,但鉴于上述限制,我正在寻找特定的 .net 方法。

    更新:我很欣赏到目前为止的答案。那个 Patrik Hägne提出来的是“为什么不提取接口(interface)?”这在一定程度上确实有效,但存在一些问题,例如现有设计有很多我们暴露具体类的情况。例如:
    public class UserRepository 
    {
    public UserData GetData(string userName)
    {
    ...
    }
    }

    期待具体类(例如“UserData”)的现有客户如果获得“IUserData”就会中断。

    此外,正如评论中提到的,有些情况下我们接收一个类,然后为了方便而公开它。如果我们接受一个接口(interface),然后不得不将它作为一个具体的类公开,这可能会导致问题。

    重大重写或重新设计的最大挑战是对当前 API 的巨大投资(数千小时的开发时间和可能同样多的第三方培训)。所以,虽然我同意更好 SOLID设计重写或抽象层(最终可能成为新的 API)专注于诸如 Interface Separation Principle 之类的项目从可测试性的角度来看,这将是一个加分项,这将是一项目前可能无法进行成本合理的大型任务。

    我们确实对当前的 API 进行了测试,但它是更复杂的集成测试而不是单元测试。

    此外,正如 Chad Myers 所提到的,这个问题解决了 .NET 框架本身在某些领域面临的类似问题。

    我意识到我可能正在寻找一个不存在的“银弹”,但感谢所有帮助。重要的部分是保护许多第三方开发人员的大量时间投资以及用于创建当前 API 的大量现有开发。

    所有的答案,尤其是那些考虑到问题的业务方面的答案,都将被仔细审查。谢谢!

    最佳答案

    您真正要问的是,“我如何根据 SOLID 和类似原则设计我的 API,以便我的 API 与其他人一起玩得很好?”这不仅仅是关于可测试性。如果你的客户在用你的代码测试他们的代码时遇到问题,那么他们在用你的代码编写/使用他们的代码时也会遇到问题,所以这是一个比可测试性更大的问题。

    简单地提取接口(interface)并不能解决问题,因为很可能您现有的类接口(interface)(具体类作为其方法/属性公开的内容)在设计时并没有考虑到接口(interface)隔离原则,因此提取的接口(interface)会出现各种问题(一些您在对先前答案的评论中提到了其中的内容)。

    我喜欢称其为 IHttpContext 问题。如您所知,由于 HttpContext.Current 的“魔术单例依赖”问题,ASP.NET 很难测试或使用它。没有像 TypeMock 使用的花哨的技巧,HttpContext 是不可模拟的。简单地提取 HttpContext 的接口(interface)不会有太大帮助,因为它太大了。最终,即使是 IHttpContext 也会成为测试的负担,以至于它几乎不值得尝试模拟 HttpContext 本身。

    确定对象职责,适本地划分接口(interface)和交互,并以开放/封闭原则进行设计,这不是您试图强行/塞进现有 API 设计而没有考虑这些原则的事情。

    我不想给你一个如此冷酷的答案,所以我会给你一个积极的建议:你如何代表你的客户承担所有的悲伤,并在你的旧 API 之上制作某种服务/外观层。这个服务层将不得不处理 API 的细节和痛苦,但会提供一个漂亮、干净、对 SOLID 友好的公共(public) API,您的客户可以使用它而减少摩擦。

    这还有一个额外的好处,即允许您慢慢替换 API 的一部分,并最终使您的新 API 不仅仅是外观,而是 API(并且旧 API 已被淘汰)。

    关于c# - 如何使现有的公共(public) API 可供使用它的外部程序员测试?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/387451/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com