【问题标题】:Best Practices for TDD in JavaScript/TypeScriptJavaScript/TypeScript 中的 TDD 最佳实践
【发布时间】:2021-09-11 05:30:11
【问题描述】:

问题

  • 访问模块中的所有 JavaScript/TypeScript 函数以进行单元测试的正确/可接受的方式是什么?
  • 我不应该只导出所有函数是否有(充分的)理由?

上下文

请原谅我的无知;我的大部分职业生涯都在使用测试驱动开发 (TDD) 方法编写 Python 代码。现在,我发现自己正在学习 ReactJS/TypeScript 并弄清楚如何实现单元测试,但我很快发现只有导出函数才能访问它们。大多数人都知道,Python 是非常宽松的。确实没有隐私的概念,因此只需导入模块并尊重您可以访问的内容。但 JavaScript 只导入已显式导出的模块的功能,因此提供了适度的障碍。

有人告诉我,导出所有函数进行测试不是一个好主意,但我不知道有另一种方法可以实际测试它们。

示例

我被告知的是“正确/更好”:

Sample1.js:

const func1 = () => {
    //code that does stuff
    return "stuff";
};

const func2 = () => {
   //code that does other stuff
   return "otherStuff";
};

export { func1 };

Sample1.test.js:

// executed via Jest framework

import * as sample from "./Sample1.js"

describe("Unit Tests for Sample1", () => {
    test("Unit Test - func1", () => {
        // code that tests stuff
    };

    test("Unit Test - func2", () => {
        // can't test func2 because it's not exported
    };
};

为了能够测试所有功能,我正在做什么:

Sample2.js:

const func1 = () => {
    //code that does stuff
    return "stuff";
};

const func2 = () => {
   //code that does other stuff
   return "otherStuff";
};

export { func1, func2 };

Sample2.test.js:

// executed via Jest framework

import * as sample from "./Sample2.js"

describe("Unit Tests for Sample2", () => {
    test("Unit Test - func1", () => {
        // code that tests stuff
    };

    test("Unit Test - func2", () => {
        // code that tests other stuff because it's exported
    };
};

记录在案

我专门在 Internet 和 Stack Overflow 上查看了标准和最佳实践,但我没有找到太多可以回答这个特定问题的内容。我找到的最接近的是this SO question,但这并不是我真正想要的。

【问题讨论】:

    标签: javascript typescript tdd standards


    【解决方案1】:

    如果您真正通过在被测系统 (SUT) 之前编写测试 来进行测试驱动开发 (TDD),那么您可以将测试视为 SUT 的可执行规范。 (如果这对您来说已经很明显了,我很抱歉,但是 Stack Overflow 上的许多人将 TDD 与单元测试互换使用,并说他们执行 TDD,即使他们在 SUT 之后编写测试。)

    因此,测试描述了 SUT 的 API。在具有access modifiers 和/或显式导出功能的语言中,您需要使 SUT 可用于测试。在 JavaScript 中,这确实意味着您必须导出要测试的 API。在具有访问修饰符的其他语言中,这也意味着您必须为 SUT API public 提供可用性(例如 Java 和 C#)。

    如果您正在开发一个库,这也将与客户端代码可用的 API 相吻合。事实上,测试是 SUT 的第一个(或最早的)客户端。

    测试到位后,它们将作为 SUT 的回归测试套件。因此,如果测试失败,则表明导出的 API 的某些部分已损坏。这也意味着该部分将被使用它的客户端代码破坏。

    那么你应该导出所有方法吗?

    不一定。您可能希望隐藏一些方法作为实现细节。这可能有各种充分的理由。也许您不确定帮助方法的 API 是否健壮,并且您希望保留在不破坏客户端代码的情况下更改它的能力。可能是辅助方法封装不好。

    只要在 TDD 过程中创建了此类辅助方法,它们就会still be transitively covered by tests,即使它们本身没有被导出。

    【讨论】:

    • 谢谢,这是一个非常有用的答案。在阅读了您的response to the other question 之后,我现在的问题是:它是一个通用的 TDD 范式来完全公开您的函数,然后在它们通过后(正确地)更改访问修饰符吗?我问是因为我一直在以完全相反的方式接近它,测试所有辅助函数,以便我可以对将它们联系在一起的主要函数充满信心。
    • @JonathanBelden 如果你一直在做相反的事情,那么我所描述的不是 universal ? 但是 " 完全公开你的功能和然后在它们通过后更改访问修饰符“ 不是我所描述的。
    • 好的,但我要问 - 与另一种方法相比,一种方法正确吗?而且,如果我正确理解“Red-Green-Refactor”,一旦通过测试,对某些代码块的访问可能会发生变化(通过将它们移动到私有帮助函数)。那么这是“正确”的做法吗?我不想争论...我只是想更好地理解 TDD 标准约定,特别是因为我在工作中负责它。
    • @JonathanBelden 然而,我意识到,在我关于这个主题的所有著作中,我都没有展示代码示例。这启发了我写a new blog post。我希望它有所帮助。
    • @TysonWilliams 我不认为这是一个解决方案——我认为它是part of the problem
    猜你喜欢
    • 1970-01-01
    • 2012-05-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-19
    • 1970-01-01
    • 2016-10-05
    • 2013-11-12
    相关资源
    最近更新 更多