我是否需要测试我知道其结果的功能?

Do I need to test functions which I know their result?

我在 UserService class 下有一些方法,它们是我的 ORM(即 Prisma)的高级抽象。我这样做的原因是,如果我决定使用另一个 ORM,我的应用程序的其余部分将不需要更改。例如,此方法创建一个用户(已简化)

export class UserService {
  async create(data: UserCreateInput) {
    return await this.prisma!.user.create({
      data: { ...data },
      select: selectUserFields(),
    });
  }
}

我的 create 方法只运行 Prisma 的创建方法和 returns 输出。我在我的 create 方法中做了更多的事情,但最终,它 return 是 Prisma 的 create 方法的结果。在测试中,我必须模拟 Prisma 的 create 方法的 return 值,然后检查它是否是我指定的,这有点傻。

  it("should create a new user ", () => {
      mockPrisma.user.create.mockResolvedValue(defaultUser);
      expect(userService.create({ name: "jack" })).resolves.toEqual(defaultUser);
  });

即使这个简单的测试也给我缓存了一些错误,比如忘记 return 一个值,但我对它给我带来的好处并不满意。我不想花时间 运行 愚蠢的测试。

你觉得它也很傻还是我应该保留它?

这个问题的答案都将基于意见并且相互矛盾,这可能意味着这个问题可以关闭。此外,很多聪明人对此发表了比我更好的意见,而且很多聪明人认为我错了......但尽管如此,我还是会尝试回答。


TL;DR 是的,保留它。如果你不想阅读数以百万计的关于什么测试是好的相互矛盾的意见,那么就在每个可能的级别上尽可能多地编写测试,直到你比任何写博客的人都更清楚答案。如果你确实想阅读一堆人对这个问题的看法,我这里有一个给你。


像 Larry Wall 这样的人说过这样的话:“我可以告诉你我是怎么做的,但我不能告诉你你是怎么做的。”

就我个人而言,我的目标是在尽可能高的水平上实现 100% 的测试覆盖率。 Jest 可以告诉您什么时候要留下未覆盖的行。我会测试 API 端点(或安装客户端组件)。
在这些情况下,我只会为单独的函数编写测试,比如你在那里的函数:

  • 该函数涵盖了太多的情况,以至于我无法或不想通过调用 API 来弄清楚如何调用它们。 日期格式化函数 就是一个很好的例子。您 API 可能取决于系统日期或类似日期,因此只能真正测试今天的日期或类似日期,因此您可以使用大约一百个样本日期来测试日期格式化程序。
  • 实际上很难首先弄清楚如何正确使用该功能..就像它有各种各样的 if else || &&它和您实际上首先从测试中受益(这类似于我听到 DHH 所说的“TDD 甜蜜点”或类似的话)
  • 无法通过高级测试获得 100% 的覆盖率。但我完全确定我需要特定的代码行,所以虽然我可以输入 /* istanbul ignore next */ 或其他内容并告诉覆盖率系统,以及我未来的自己,我没有测试那行代码,相反,我只是像你说的那样编写一个“愚蠢”的测试来证明我是认真的,并在我的代码中评论为什么它是必要的,以及什么现实世界的情况是,出于某种原因,我的高级测试无法涵盖此代码需要工作的原因。

你的例子的另一方面是很多人说你不需要测试外部系统和外部库,特别是如果它们是著名的和可靠的。然而,最大的危险不是 Prism 不能正常工作——而是你错误地使用它。在您的示例中,您使用的是 their mock.. 这很棒...因为您希望他们已经确保他们的 mock 足够好地代表他们的库,所以您知道您正确使用他们的图书馆。如果您为外部库创建自己的模拟,它并不能真正证明任何事情,因为您的模拟可能反映出您对外部库工作方式的误解。

此外,如果您更新到下一个主要的 prism 版本,这可能会很快告诉您是否需要更改包装器方法...这很棒。因此,如果您想忽略我写的其他所有内容,请为此保留您的愚蠢测试。

最重要的是,如果您尽可能多地测试所有内容...您将很快对需要哪些测试有自己的答案,并且您自己的答案将与其他人的答案一样好。那我希望你回来回答这个问题。我会把它加入书签以防万一