【问题标题】:What is the point of mocking the method of an external library when unit testing?单元测试时模拟外部库的方法有什么意义?
【发布时间】:2019-06-21 18:55:17
【问题描述】:

单元测试的时候mock外部库的方法有什么意义?

假设我有一个函数,它使用 XYZ 库使用给定的授权令牌获取当前用户,然后如果找到该用户,它会返回一个有效的 AWS 策略:

export const getUser = async token => {
  const user = await XYZ.getUser(token)
  return {
    // valid policy
    context: user,
  }
}

如果给出的令牌无效,getUser 应该会抛出错误。

  • 如果XYZ.getUser 已经经过良好测试,那么测试此功能有什么意义?
  • 为什么要模拟 getUser 而不是使用真实的?

【问题讨论】:

  • 您想知道为什么要模拟getUser 或为什么要模拟XYZ.getUser

标签: javascript node.js unit-testing testing


【解决方案1】:

由于以下原因,您不希望为 XYZ.getUser(token) 调用实际的 HTTP 请求。

1) 单元测试的目的是测试特定的行为,在您的情况下,它是测试您的 getUser 函数是否真正有效。

2) 您不希望向后端发出实际请求,因为这通常意味着从数据库中写入/读取/删除某些内容。在许多情况下,将单元测试过度复杂化并不是一个好主意,因为此类操作不应在前端进行测试,因为您希望限制和简化单元测试以测试非常具体的行为。

3) 由于主要目标是测试上述行为,您需要简化和限制您正在测试的内容。因此,您需要了解XYZ.getUser(token) 的网络请求的单元测试应该在服务器端完成,而不是在客户端(或前端)。

4)通过mock来自XYZ.getUser(token)的响应,我们可以模拟多种场景和响应,比如成功响应(代码200 OK),以及其他类型的错误(来自后端的业务逻辑错误,或者网络错误如错误 400、500 等)。您可以通过硬编码来自XYZ.getUser(token) 的所需 JSON 响应来针对您需要测试的不同类型的场景进行此操作。

【讨论】:

    【解决方案2】:

    这又回到了单元测试的定义和用法。

    单元测试应该测试定义良好的功能,例如,您可能编写一个算法并且其功能定义得非常好。然后,因为您知道它应该如何工作,所以您将对其进行单元测试。

    根据定义,单元测试并不涉及任何外部系统,例如但不限于文件、API、数据库,以及任何需要超出逻辑单元(即您要测试的代码)的东西。

    有多种原因,其中包括执行速度。调用 API 或使用第三方调用需要一段时间。当您查看一个测试时,这不是问题,但是当您有 500 个或更多测试时,延迟将很重要。主要思想是你应该一直运行你的单元测试,非常快,你会立即得到反馈,是否有任何问题,我是否在系统的其他部分破坏了某些东西。在任何成熟的系统中,您都会将这些测试作为 CI/CD 流程的一部分运行,您不能等待太久才能完成。不,他们需要在几秒钟内运行,这就是为什么你有他们应该或不应该接触的规则。

    您模拟外部事物,以提高执行速度并消除第三方问题,因为您真的只想测试自己的代码。

    如果您调用第三方 API 并且它们因维护而停机怎么办?这是否意味着您不能因为它们而测试您的代码?

    现在,关于模拟的话题,不要过多地滥用它,如果您以函数式方式编写代码,那么您可以消除对大量模拟的需要。传递数据,而不是传递或硬编码依赖项。这使得更改输入数据变得非常容易,而无需进行太多模拟。您在使用集成/e2e 测试的同时测试系统,这可以确保您的依赖关系已正确解决。

    【讨论】:

      猜你喜欢
      • 2021-03-12
      • 2018-07-20
      • 2020-01-03
      • 2023-02-19
      • 2014-04-16
      • 2019-02-03
      • 2015-10-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多