<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ 单元测试 - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ freeCodeCamp 是一个免费学习编程的开发者社区，涵盖 Python、HTML、CSS、React、Vue、BootStrap、JSON 教程等，还有活跃的技术论坛和丰富的社区活动，在你学习编程和找工作时为你提供建议和帮助。 ]]>
        </description>
        <link>https://www.freecodecamp.org/chinese/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ 单元测试 - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/chinese/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Mon, 11 May 2026 15:33:10 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/chinese/news/tag/unit-testing/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ 如何开始对 JavaScript 代码进行单元测试 ]]>
                </title>
                <description>
                    <![CDATA[ 原文：How to Start Unit Testing Your JavaScript Code [https://www.freecodecamp.org/news/how-to-start-unit-testing-javascript/]，作者： Ondrej Polesny [https://www.freecodecamp.org/news/author/ondrej/] 我们都知道我们应该写单元测试。但是，很难知道从哪里开始，也很难知道与实际的实现相比，应该在测试上投入多少时间。那么，该从哪里开始呢？而且，除了测试代码，单元测试还有其他好处吗？ 在这篇文章中，我将解释不同类型的测试，以及单元测试给开发团队带来哪些好处。我将展示Jest——一个JavaScript测试框架。 不同类型的测试 在我们深入了解单元测试的具体内容之前，我想对不同类型的测试做一个快速介绍。它们经常被混淆，我并不感到惊讶。有时它们之间的界限很小。 单元测试 单元测试只测试你实现的单一部分，即一个单元，没有依赖关系或集成，没有框架的具体内容。它们就像一个方法，在一个特定的语言中返回一个链接：  ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/how-to-start-unit-testing-javascript/</link>
                <guid isPermaLink="false">6247ffbd99ec7406219e5388</guid>
                
                    <category>
                        <![CDATA[ 单元测试 ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ luojiyin ]]>
                </dc:creator>
                <pubDate>Fri, 01 Apr 2022 11:30:00 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2022/04/ferenc-almasi-EWLHA4T-mso-unsplash-1.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>原文：<a href="https://www.freecodecamp.org/news/how-to-start-unit-testing-javascript/">How to Start Unit Testing Your JavaScript Code</a>，作者：<a href="https://www.freecodecamp.org/news/author/ondrej/">Ondrej Polesny</a></p><!--kg-card-begin: markdown--><p>我们都知道我们应该写单元测试。但是，很难知道从哪里开始，也很难知道与实际的实现相比，应该在测试上投入多少时间。那么，该从哪里开始呢？而且，除了测试代码，单元测试还有其他好处吗？</p>
<p>在这篇文章中，我将解释不同类型的测试，以及单元测试给开发团队带来哪些好处。我将展示Jest——一个JavaScript测试框架。</p>
<h2 id="">不同类型的测试</h2>
<p>在我们深入了解单元测试的具体内容之前，我想对不同类型的测试做一个快速介绍。它们经常被混淆，我并不感到惊讶。有时它们之间的界限很小。</p>
<h3 id="">单元测试</h3>
<p>单元测试只测试你实现的单一部分，即一个单元，没有依赖关系或集成，没有框架的具体内容。它们就像一个方法，在一个特定的语言中返回一个链接：</p>
<pre><code class="language-js">export function getAboutUsLink(language){
  switch (language.toLowerCase()){
    case englishCode.toLowerCase():
      return '/about-us';
    case spanishCode.toLowerCase():
      return '/acerca-de';
  }
  return '';
}
</code></pre>
<h3 id="">集成测试</h3>
<p>在某些时候，你的代码与数据库、文件系统或其他第三方进行通信。它甚至可能是你应用程序中的另一个模块。</p>
<p>这一块的实现应该由集成测试来测试。它们通常有一个更复杂的设置，包括准备测试环境、初始化依赖关系，等等。</p>
<h3 id="">功能测试</h3>
<p>单元测试和集成测试让你相信你的应用程序可以正常工作。功能测试从用户的角度来观察应用程序，并测试系统是否按预期工作。</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/03/presentation.jpg" alt="presentation" width="600" height="400" loading="lazy"></p>
<p>在上图中，你看到单元测试构成了你的应用程序测试套件的最基础的东西。通常情况下，它们很小，有很多，而且是自动执行的。</p>
<p>所以现在让我们更详细地了解一下单元测试。</p>
<h2 id="">我为什么要写单元测试？</h2>
<p>每当我问开发者是否为他们的应用程序写了测试，他们总是告诉我："我没有时间写" 或者 "我不需要，我知道它能用"。</p>
<p>所以我礼貌地笑了笑，告诉他们我想告诉你的事情——单元测试不仅仅是为了测试。它们也在其他方面帮助你，所以你可以：</p>
<p><strong>对你的代码工作有信心。</strong> 你上次提交代码修改，构建失败，一半的应用程序停止工作是什么时候？我的是上周。</p>
<p>但那还是可以的。真正的问题是，当构建成功，改变被部署，你的应用程序开始不稳定。</p>
<p>当这种情况发生时，你开始对你的代码失去信心，最终只是祈祷应用程序能够正常工作。单元测试将帮助你更快地发现问题并获得信心</p>
<p><strong>做出更好的架构决定。</strong> 代码会发生变化，但关于平台、模块、结构等的一些决定需要在项目的早期阶段做出。</p>
<p>当你在一开始就开始考虑单元测试时，它将帮助你更好地架构你的代码，实现适当的关注点分离。你将不会被诱惑为单一的代码块分配多个功能，因为这些将是单元测试的恶梦。</p>
<p><strong>在编码之前</strong>，你写下函数方法，并立即开始实现它。哦，但是如果一个参数是空的，应该怎么办？如果它的值超出了预期范围或者包含了太多的字符怎么办？你是抛出一个异常还是返回null？</p>
<p>单元测试将帮助你发现所有这些情况。再看一下这些问题，你会发现这正是定义你的单元测试案例的内容。</p>
<p>我相信写单元测试还有很多好处。这些只是我从我的经验中回忆起来的。那些是我通过艰苦的方式学到的。</p>
<h2 id="javascript">如何编写你的第一个JavaScript单元测试</h2>
<p>但是，让我们回到JavaScript上来。我们将从<a href="https://jestjs.io/">Jest</a> 开始，它是一个JavaScript测试框架。它是一个能够实现自动单元测试的工具，提供代码覆盖率，并让我们轻松地模拟对象。Jest也有一个Visual Studio Code的扩展，<a href="https://marketplace.visualstudio.com/items?itemName=Orta.vscode-jest">可在此获得</a>。</p>
<p>还有其他的框架，如果你感兴趣，你可以在 <a href="https://www.browserstack.com/guide/top-javascript-testing-frameworks">本文</a> 中查看它们。</p>
<pre><code class="language-js">npm i jest --save-dev
</code></pre>
<p>Let's use the previously mentioned method <code>getAboutUsLink</code> as an implementation we want to test:</p>
<pre><code class="language-js">const englishCode = "en-US";
const spanishCode = "es-ES";
function getAboutUsLink(language){
    switch (language.toLowerCase()){
      case englishCode.toLowerCase():
        return '/about-us';
      case spanishCode.toLowerCase():
        return '/acerca-de';
    }
    return '';
}
module.exports = getAboutUsLink;
</code></pre>
<p>我把它放在<code>index.js</code>文件中。我们可以在同一个文件中写测试，但一个好的做法是将单元测试分离到一个专门的文件中。</p>
<p>常见的命名模式包括<code>{filename}.test.js</code>和<code>{filename}.spec.js</code>。我使用了第一种，<code>index.test.js</code>:</p>
<pre><code class="language-js">const getAboutUsLink = require("./index");
test("Returns about-us for english language", () =&gt; {
    expect(getAboutUsLink("en-US")).toBe("/about-us");
});
</code></pre>
<p>首先，我们需要导入我们要测试的函数。每个测试都被定义为对 <code>test</code> 函数的调用。第一个参数是测试的名称，供你参考。另一个是一个箭头函数，我们在这里调用我们要测试的函数，并指定我们期望的结果。</p>
<p>在这个例子中，我们调用 <code>getAboutUsLink</code> 函数，语言参数为 <code>en-US</code>。我们期望的结果是 "/about-us"。</p>
<p>现在我们可以全局安装Jest CLI并运行测试：</p>
<pre><code class="language-js">npm i jest-cli -g
jest
</code></pre>
<p>如果你看到一个与配置有关的错误，确保你有 <code>package.json</code> 文件。如果你没有，可以用 <code>npm init</code> 生成一个。</p>
<p>你应该看到类似这样的东西：</p>
<pre><code class="language-js"> PASS  ./index.test.js
  √ Returns about-us for english language (4ms)
  console.log index.js:15
    /about-us
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        2.389s
</code></pre>
<p>很棒！这是第一个从头到尾的简单JavaScript单元测试。如果你安装了Visual Studio Code扩展，一旦你保存一个文件，它就会自动运行测试。让我们用这一行扩展测试来试试吧：</p>
<pre><code class="language-js">expect(getAboutUsLink("cs-CZ")).toBe("/o-nas");
</code></pre>
<p>一旦你保存文件，Jest就会通知你测试失败。这有助于你在提交修改之前就发现潜在的问题。</p>
<h2 id="mocking">测试高级功能和 Mocking（模拟） 服务</h2>
<p>在现实生活中，getAboutUsLink方法的语言代码不会在同一个文件中成为常量。它们的值通常会在整个项目中使用，所以它们会被定义在自己的模块中，并被导入到所有使用它们的函数中。</p>
<pre><code class="language-js">import { englishCode, spanishCode } from './LanguageCodes'
</code></pre>
<p>你可以用同样的方法将这些常量导入测试中。但是如果你要处理对象而不是简单的常量，情况会变得更加复杂。看看这个方法吧：</p>
<pre><code class="language-js">import { UserStore } from './UserStore'
function getUserDisplayName(){
  const user = UserStore.getUser(userId);
  return `${user.LastName}, ${user.FirstName}`;
}
</code></pre>
<p>这个方法使用了导入 <code>UserStore</code>：</p>
<pre><code class="language-js">class User {
    getUser(userId){
        // logic to get data from a database
    }
    setUser(user){
        // logic to store data in a database
    }
}
let UserStore = new User();
export { UserStore }
</code></pre>
<p>为了正确地单元测试这个方法，我们需要 mock(模拟) <code>UserStore</code>。 mock 是原始对象的一个替代品。它允许我们将依赖关系和真实数据与测试方法的实现分开，就像假人帮助汽车的碰撞测试而不是真人一样。</p>
<p>如果我们不使用mock，我们就会同时测试这个函数和商店。这将是一个集成测试，我们很可能需要对使用的数据库进行 mock（模拟）。</p>
<h3 id="mocking">Mocking（模拟） 一个服务</h3>
<p>为了 mock(模拟) 对象，你可以提供一个 mock 函数或一个手动 mock。我将专注于后者，因为我有一个简单的用例。但你可以自由地<a href="https://jestjs.io/docs/en/mock-functions.html">查看Jest其他的提供者（provides）</a>。</p>
<pre><code class="language-js">jest.mock('./UserStore',&nbsp;()&nbsp;=&gt;&nbsp;({
&nbsp;&nbsp;&nbsp;&nbsp;UserStore:&nbsp;({
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;getUser:&nbsp;jest.fn().mockImplementation(arg&nbsp;=&gt;&nbsp;({
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FirstName:&nbsp;'Ondrej',
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LastName:&nbsp;'Polesny'
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;})),
        setUser: jest.fn()
&nbsp;&nbsp;&nbsp;&nbsp;})
}));
</code></pre>
<p>首先，我们需要指定我们 mock(模拟) 的是什么 - <code>./UserStore</code> 模块。接下来，我们需要返回包含该模块所有导出对象的模拟。</p>
<p>在这个例子中，只有名为<code>UserStore</code> 的 <code>User</code> 对象和 <code>getUser</code> 函数。但在真正的实现中，模拟对象可能更长。在单元测试的范围内，任何你并不真正关心的函数都可以用 <code>jest.fn()</code> 轻松地 Mock(模拟)。</p>
<p>函数 <code>getUserDisplayName</code>的单元测试与我们之前创建的类似:</p>
<pre><code class="language-js">test("Returns&nbsp;display&nbsp;name",&nbsp;()&nbsp;=&gt;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;expect(getUserDisplayName(1)).toBe("Polesny,&nbsp;Ondrej");
})
</code></pre>
<p>当我保存文件时，Jest告诉我有两个通过的测试。如果你正在手动执行测试，现在就这样做，确保你看到同样的结果。</p>
<h3 id="codecoveragereport">Code Coverage Report</h3>
<p>现在我们知道了如何测试JavaScript代码，用测试覆盖尽可能多的代码是很好的。而这是很难做到的。说到底，我们只是人。我们想完成我们的任务，而单元测试通常会产生一些无意义的工作量，我们往往会本能的忽略。代码覆盖率统计工具是一个帮助我们对抗这种情况。</p>
<p>代码覆盖率会告诉你，你的代码有多大一部分被单元测试所覆盖。以我的第一个单元测试为例，检查<code>getAboutUsLink</code> 函数:</p>
<pre><code class="language-js">test("Returns about-us for english language", () =&gt; {
&nbsp;&nbsp;&nbsp;expect(getAboutUsLink("en-US")).toBe("/about-us");
});
</code></pre>
<p>它检查了英文链接，但西班牙文版本仍未被测试。代码覆盖率为50%。另一个单元测试是彻底检查 <code>getDisplayName</code>函数，其代码覆盖率为100%。总之，总的代码覆盖率是67%。我们有3个用例需要测试，但我们的测试只覆盖了其中的两个。</p>
<p>要查看代码覆盖率报告，请在终端输入以下命令：</p>
<pre><code class="language-js">jest --coverage
</code></pre>
<p>或者，如果你使用的是带有Jest扩展的Visual Studio Code，你可以运行命令（CTRL+SHIFT+P 组合快捷键调出，然后输入）<em>Jest。 触发执行 Coverage Overlay</em>。它将在实现中直接显示哪些代码行没有被测试覆盖。</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/03/code-coverage-inline.jpg" alt="code-coverage-inline" width="600" height="400" loading="lazy"></p>
<p>通过运行覆盖率检查，Jest还将创建一个HTML报告。在你的项目文件夹中的<code>coverage/lcov-report/index.html</code>下找到它。</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/03/code-coverage.jpg" alt="code-coverage" width="600" height="400" loading="lazy"></p>
<p>现在，我不用再提了，你应该争取100%的代码覆盖率，对吗？:-)</p>
<h2 id="">总结</h2>
<p>在这篇文章中，我向你展示了如何在JavaScript中开始单元测试。虽然在报告中让你的代码覆盖率达到100%是件好事，但在现实中，并不总是能够（有意义地）达到这个目标。我们的目标是让单元测试帮助你维护你的代码，并确保它总是按照预期工作。它们使你能够：</p>
<ul>
<li>明确定义实现需求</li>
<li>更好地设计你的代码和分离关注点</li>
<li>发现你在较新的提交中尽早发现问题</li>
<li>并让你相信你的代码是正常工作的</li>
</ul>
<p>最好的开始是Jest文档中的 <a href="https://jestjs.io/docs/en/getting-started">Getting started（入门）</a> 页面，这样你就可以自己尝试这些做法了。</p>
<p>你对测试代码有自己的经验吗？我很想听听，请在 <a href="https://twitter.com/ondrabus">Twitter</a> 上告诉我，或者加入我的 <a href="https://twitch.tv/ondrabus">Twitch streams 直播频道</a>。</p>
<!--kg-card-end: markdown--> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ 玩转单元测试之巧妙处理依赖 ]]>
                </title>
                <description>
                    <![CDATA[ 我们平时使用的网络请求库 Axios 等，这些对我们的项目来说都是依赖。可以说依赖无处不在，它的存在更容易发起网络请求，格式化时间等，但同样也带来了问题——很难为代码编写单元测试。 0x01 我们开始吧 在正式进入主题之前，我会先告诉你，为了让我们的单测达到 F.A.I.R 原则的标准，我们需要解决的问题是：  1. 功能代码使用良好的设计，对依赖进行解耦，尽可能去除依赖；  2. 实在去除不了的依赖，如内部依赖，通过依赖注入构建松耦合的代码。测试代码使用一些技术进行替代，我们称这些技术叫测试替身 - 包括     Dummy、Fake、Stub、Mock和Spy。 需求：通过getCurrentPosition函数获取经纬度，定义一个供百度地图使用的 URL ，将该 URL 赋值给 window.location 。如果获取位置失败，则设置一条错误消息。 通过简单的需求分析和任务拆分，都会认为这个需求很简单。可是我们如何为它写自动化测试呢？没有写过UT的我，刚开始也是很懵的。跟我刚开始被要求为功能写单元测试的时候一样懵，完全不知道从那入手~我在搜索引擎中找到了一个解决方法，  ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/handle-unit-testing-dependency/</link>
                <guid isPermaLink="false">5fa2b5145f583f0565090da3</guid>
                
                    <category>
                        <![CDATA[ 敏捷开发 ]]>
                    </category>
                
                    <category>
                        <![CDATA[ 单元测试 ]]>
                    </category>
                
                    <category>
                        <![CDATA[ 依赖 ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ 易海门 ]]>
                </dc:creator>
                <pubDate>Wed, 04 Nov 2020 09:19:00 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2021/04/photo-1593642532400-2682810df593.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>我们平时使用的网络请求库 Axios 等，这些对我们的项目来说都是依赖。可以说依赖无处不在，它的存在更容易发起网络请求，格式化时间等，但同样也带来了问题——很难为代码编写单元测试。</p><h2 id="0x01-"><strong>0x01 我们开始吧</strong></h2><p>在正式进入主题之前，我会先告诉你，为了让我们的单测达到 F.A.I.R 原则的标准，我们需要解决的问题是：</p><ol><li>功能代码使用良好的设计，对依赖进行解耦，尽可能去除依赖；</li><li>实在去除不了的依赖，如内部依赖，通过依赖注入构建松耦合的代码。测试代码使用一些技术进行替代，我们称这些技术叫测试替身 - 包括 Dummy、Fake、Stub、Mock和Spy。</li></ol><p>需求：通过getCurrentPosition函数获取经纬度，定义一个供百度地图使用的 URL ，将该 URL 赋值给 window.location 。如果获取位置失败，则设置一条错误消息。</p><p>通过简单的需求分析和任务拆分，都会认为这个需求很简单。可是我们如何为它写自动化测试呢？没有写过UT的我，刚开始也是很懵的。跟我刚开始被要求为功能写单元测试的时候一样懵，完全不知道从那入手~我在搜索引擎中找到了一个解决方法，<a href="https://blog.ming.ws/posts/read/10x-develop-technique/technical-spkie/#post">《如何分解一个你不了解的技术任务？ Technical spkie》</a>。</p><h3 id="1-spike-"><strong>1、借助 Spike 技术编写原型代码</strong></h3><figure class="kg-card kg-image-card"><img src="https://s1.ax1x.com/2020/07/21/UTnzh6.png" class="kg-image" alt="https://s1.ax1x.com/2020/07/21/UTnzh6.png" title="origin-code" width="600" height="400" loading="lazy"></figure><h3 id="2-"><strong>2、从中获得一些信息</strong></h3><ul><li>getCurrentPosition 是一个异步函数，包含成功和失败两个回调函数</li><li>获取到经纬度时，拼接成一条 url</li><li>未获取到经纬度时，设置错误信息</li><li>将 url 赋值给 location，此时浏览器会发生重定向</li></ul><p>通过对原型代码的观察，发现其可测试性很差，而我们知道代码是否具有可测试性是个设计问题。所以，我们将解决第一个问题，即尽可能去除被测代码中的依赖。抽取函数，并将最少的数据作为参数传给它，对代码进行模块化设计。</p><h3 id="3-"><strong>3、模块化设计</strong></h3><p>有没有发现自己很多时候写的代码其实是原型代码，并没有设计可言！很多时候不写测试，根本发现不了这些问题，也不会对代码的设计有任何想法，更不用说什么设计模式地使用了。</p><p>接下来我们将 spike 阶段的原型代码进行拆分，是每个小功能都是一个小函数，每个小函数具有单一职责和最少依赖的特征。</p><figure class="kg-card kg-image-card"><img src="https://s1.ax1x.com/2020/07/21/UTu4DH.jpg" class="kg-image" alt="https://s1.ax1x.com/2020/07/21/UTu4DH.jpg" title="设计流程图" width="600" height="400" loading="lazy"></figure><p>下边需要做的就是为每一个函数编写自动化测试，以验证它们的行为。 依赖在整个问题中占据了很重要的作用，编写自动化测试的第一步就是确定一个或多个不具有内部依赖的函数，这些函数应该成为自动化测试的起点。</p><p>createUrl 就是我们要找函数，因为它没有任何其他依赖的代码测起来相对容易，只需要接收到正确的位置信息，然后创建一条符合预期的URL 就可以了。</p><p>接下来根据测试列表中的用例为其编写同步测试、反向测试、异常测试，之前介绍过方法就不再赘述了。</p><h3 id="4-"><strong>4、使用测试替身</strong></h3><p>接下来就是有依赖需要处理的函数，我们需要使用替身来解决第二个问题。</p><p>什么是替身？ 代替真正依赖的对象，从而让自动化测试可以进行。就好比电影中的替身演员，当主角完不成不了某专业且高难度的动作时，此时替身演员就会上场，而替身演员的目的是为了让电影继续拍下去，比如主角没有找替身，要是残了的话，这部电影岂不是拍不下去了？！ 如果还不了解这五种类型的测试替身，可以先花点时间看看<a href="https://martinfowler.com/articles/mocksArentStubs.html">这篇文章</a>。</p><p>我们将为依赖 window 对象的 location 属性的 setLocation 函数编写测试。首先试想一下，我们在没有单元测试的时候，是不是这样调试的？在这个方法打一个断点，看url是不是创建成功，然后下一步看浏览器是不是跳转了。事实上，这样是很费时费力的，目前我们需要解决的问题是： 我们给一个window对象的location属性设置值之后，验证其正确性，而不是浏览器做出来什么响应，并且是能使用单元测试不要使用UI测试（测试金字塔）。 怎么解决？ 为window对象注入一个stub。</p><p>在正式开始前，我们还需要了解什么是依赖注入： 依赖注入是用测试替身代替依赖的一种流行、通用的技术。也就是说依赖是作为一个参数传递给函数的，而不是直接在函数中引用的。</p><figure class="kg-card kg-image-card"><img src="https://s1.ax1x.com/2020/07/21/UTK95q.png" class="kg-image" alt="https://s1.ax1x.com/2020/07/21/UTK95q.png" title="UTK95q.png" width="600" height="400" loading="lazy"></figure><h3 id="5-"><strong>5、交互测试</strong></h3><p>什么是交互测试？ 在了解交互测试之前，我们先回顾一下之前为同步和异步函数编写的测试，给定特定的参数，它们的预期值始终是不变的，我们把这些测试称为经验测试 ~ 结果是确定的、可预测的，且很容易断定的。 但当我们涉及依赖时，其结果是很难预测的。在编写测试时，需要将注意力放在函数的行为，而不是函数依赖对象是否正确。也就是说我们不需要管这个对象是真是假，只需要检查代码能够以正确的方式与依赖对象进行交互就好了。当函数的依赖成功执行或执行失败时，函数是否进行了正确的处理。我们称这为交互测试 ~ 代码中有很复杂的依赖关系，而且依赖让代码不确定、难以预测、脆弱或耗时。</p><p>接下来将使用交互测试为locate函数编写测试用例了。在locate函数中，我们依赖一个异步函数getCurrentPosition去获取当前位置，需要注意的是我们无法确定“当前”位置的准确度，不能依赖这个结果，故根据上边的总结得出我们就没有必要采取经验测试了。</p><p>最终，我们需要使用交互测试，专注验证locate函数与getCurrentPosition函数的交互行为，而不是验证getCurrentPosition函数最终返回了正确的位置。因为是为了验证locate函数是否调用了它依赖的函数，所以使用测试替身mock来代替getCurrentPosition函数。但为啥没有使用依赖注入呢？这是因为navigator的属性比location的属性更容易模拟。我们首先复制了getCurrentPosition函数，然后给了它一个模拟的函数，最后又将其还原。这个方法的好处就是让测试变得快速，且可预测。并且我们不用处理是否允许浏览器获取用户位置的问题。</p><p>在模拟函数中检查传入的两个参数是否是对onSuccess和onError函数的引用。会存在三种情况： 1、调用了getCurrentPosition函数，并传递了预期的回调函数，测试通过； 2、调用了getCurrentPosition函数，没有传递了预期的回调函数，测试失败； 3、没有调用getCurrentPosition函数，测试失败。</p><figure class="kg-card kg-image-card"><img src="https://s1.ax1x.com/2020/07/21/UTKMPx.png" class="kg-image" alt="https://s1.ax1x.com/2020/07/21/UTKMPx.png" title="UTKMPx.png" width="600" height="400" loading="lazy"></figure><h2 id="0x02-"><strong>0x02 总结</strong></h2><p>通过我自己的学习与实践，得知道理都懂，还是需要多练多看，不然还是不知道如何下手。在真正学会测试驱动代码设计之后呢，就需要学会如何识别‘坏味道’即重构手法，这也是需要平时的积累。最后就是去学习能提高效率的指法和快捷键的使用。</p><p>最后，接下来根据自己的计划，需要学习数据结构了，同时也需要进一步去实践单元测试，之后至少会出一篇 Node.js 的单元测试策略和一篇 React 的单元测试策略的文章。</p><p>最后，接下来根据自己的计划，需要学习数据结构了，同时也需要进一步去实践单元测试，之后至少会出一篇 Node.js 的单元测试策略和一篇 React 的单元测试策略的文章。</p><h2 id="0x03-"><strong>0x03 参考</strong></h2><ul><li>《JavaScript测试驱动开发》</li><li>Jest 官网</li></ul> ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
