Unit testing 为第三方库测试智能包装器

Unit testing 为第三方库测试智能包装器,unit-testing,testing,tdd,integration,integration-testing,Unit Testing,Testing,Tdd,Integration,Integration Testing,假设您需要使用一个不必要的复杂、难以模拟的(可能它有没有虚拟接口的具体类)和不可靠的第三方库,该库集成了一些外部资源,如套接字或数据库。您决定创建“包装器”接口/类,以大大简化此库的使用,并允许使用包装器的开发人员继续编写可测试代码。包装器的接口与原始接口完全不同 关于如何测试这个包装器,我有几个问题 是否应该在没有外部资源的情况下,通过在可以模拟的坏库上为方法层开发一个方法来测试包装器 当您使用第三方库(使用外部资源)测试包装器类时,这是单元测试还是集成测试?如果在自动化测试期间可以将外部资源

假设您需要使用一个不必要的复杂、难以模拟的(可能它有没有虚拟接口的具体类)和不可靠的第三方库,该库集成了一些外部资源,如套接字或数据库。您决定创建“包装器”接口/类,以大大简化此库的使用,并允许使用包装器的开发人员继续编写可测试代码。包装器的接口与原始接口完全不同

关于如何测试这个包装器,我有几个问题

  • 是否应该在没有外部资源的情况下,通过在可以模拟的坏库上为方法层开发一个方法来测试包装器

  • 当您使用第三方库(使用外部资源)测试包装器类时,这是单元测试还是集成测试?如果在自动化测试期间可以将外部资源嵌入内存中,那么它仍然是一个集成测试吗

  • 什么时候我们才能停止嘲笑和指责,说我们有一个单位。根据维基百科的说法,“单元是应用程序中最小的可测试部分。”但我发现这很难衡量。如果速度是决定我们是否测试一个单元的一个因素,那么您如何决定速度有多慢对于称为单元测试的测试来说太慢


  • TDD并没有说所有的东西都必须经过单元测试。TDD说您应该首先编写一个测试,但它不一定是一个单元测试

  • 从集成测试开始——它将测试依赖于包装器的逻辑,包装器将与真实组件通信。这里没有嘲弄。这是集成测试,因为它测试应用程序的多个层,而真正的组件仍然使用套接字或数据库访问
  • 集成测试将失败,因为您没有逻辑
  • 使用模拟包装器编写单元测试以测试逻辑
  • 单元测试将失败,因为您没有逻辑
  • 编写逻辑以满足单元测试(4)
  • 重复3-5次。获得满足集成测试(1)所需的所有逻辑
  • 在下一次集成测试中重复整个过程
  • 不需要为包装器编写单元测试。主包装器的功能是包装组件。如果您为包装器编写单元测试,您将测试它是否调用组件上的方法,但在这种情况下,您又回到了开始——如何模拟组件?如果您只为调用组件的包装器编写集成测试,那么您正在重新测试组件(好的,这有时很方便,但在正常情况下您不会这样做)


    我推荐史蒂夫·弗里曼(Steve Freeman)和纳特·普赖斯(Nat Pryce)的作品。

    我认为这个问题的核心是这句话:

    包装器的接口与原始接口完全不同

    这可能表明包装器和原始接口之间的转换涉及大量逻辑。这听起来很像一个逻辑,如果这个逻辑很复杂,就应该进行测试

    最好的方法仍然是从原始API中提取1:1接口。但是,这不是您向应用程序的其余部分公开的接口。您向应用程序的其余部分公开的接口可以是在提取的接口之上的接口。在某种意义上,您可以说提取的接口是反腐败层的一个实现细节,而不是向应用程序的其余部分公开的东西

    这使您能够对Facade接口和提取接口之间的转换进行单元测试,同时仍然将原始的、难以测试的组件排除在测试之外

    剩下的是提取的接口和原始组件之间的转换。但是,如果该接口被提取为原始组件的1:1映射,那么实现应该由纯委托组成。换句话说,实现的圈复杂度为1,因此是一个不需要进行单元测试的复杂度

    您可能仍然希望在已完成的系统上进行一些集成或系统测试,但这些测试可能起到冒烟测试的作用,因为您应该已经从单元测试中获得了足够的覆盖率。

    Ad 1)不是简单的答案。包装器除了包装外,不应该做其他任何事情。因此,集成测试是唯一有意义的事情

    是的


    Ad 3)当您的目标对象只做一件事时,您停止,让外部对象(注入的和可模仿的)做其他事情(SRP)

    +1我想,如果包装器/外观最终超过了方法委托,那么它可能变得足够复杂,足以证明有足够的时间创建一个1:1“哑”包装器来隔离逻辑。很好。