<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Salesforce Engineering</title>
    <description>The latest articles on DEV Community by Salesforce Engineering (@salesforceeng).</description>
    <link>https://dev.to/salesforceeng</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F775%2F05a592d4-05c4-4f31-83aa-6b5d1df71be5.png</url>
      <title>DEV Community: Salesforce Engineering</title>
      <link>https://dev.to/salesforceeng</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/salesforceeng"/>
    <language>en</language>
    <item>
      <title>Using Testify Mock in web clients</title>
      <dc:creator>Andy Haskell</dc:creator>
      <pubDate>Mon, 24 Oct 2022 14:08:12 +0000</pubDate>
      <link>https://dev.to/salesforceeng/using-testify-mock-in-web-clients-5amb</link>
      <guid>https://dev.to/salesforceeng/using-testify-mock-in-web-clients-5amb</guid>
      <description>&lt;p&gt;In the last tutorial, we looked at:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How Testify Mock helps us make nondeterministic code testable&lt;/li&gt;
&lt;li&gt;How to implement an interface using an embedded Testify Mock&lt;/li&gt;
&lt;li&gt;What the general flow of a Testify Mock test looks like&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We demonstrated that on random numbers first, since that's the simplest nondeterministic code to be working with.&lt;/p&gt;

&lt;p&gt;However, the use case of Testify Mock that ultimately got me learning about that package, was to use it in code that builds on top of &lt;strong&gt;clients to web APIs&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The reason code using web API clients is nondeterministic to test is, you don't have total control over what you get back from a web server for a given input, for reasons such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✍️ The data you get back for a given server endpoint might change, either slightly or dramatically.&lt;/li&gt;
&lt;li&gt;🚧 The server might be down altogether.&lt;/li&gt;
&lt;li&gt;🐆 You might be being rate-limited from sending too many requests to the server.&lt;/li&gt;
&lt;li&gt;🐛 You'll want test coverage so that your code does the right thing if the server you're talking to is giving back 500s. But since a 500 by definition is an internal server error, it's not necessarily possible to &lt;strong&gt;reliably&lt;/strong&gt; get 500s, especially in the long term.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So for tests where you want the same output &lt;strong&gt;every time you run the same API client call in your test&lt;/strong&gt;, that's a great use case for Testify Mock. So for this tutorial, we'll see how Testify Mock can be used as one of your tools to write test coverage when your Go code's got some Internet to do!&lt;/p&gt;

&lt;h2&gt;
  
  
  📚 Setting up a fake API to test against
&lt;/h2&gt;

&lt;p&gt;The code we're going to test uses a client for an API that the zoo set up to give facts about animals.&lt;/p&gt;

&lt;p&gt;The endpoint our code will be talking to is &lt;code&gt;GET /animal-facts?species={species}&amp;amp;page-token={page-token}&lt;/code&gt;, and it returns a JSON object containing a page worth of animal facts, plus a token if there's another page.&lt;/p&gt;

&lt;p&gt;If you're following along, copy the code ahead into a file named something like &lt;code&gt;client.go&lt;/code&gt;. The main takeaway is that we have a &lt;code&gt;ZooHTTPClient&lt;/code&gt; for talking to the zoo's API, and we call the &lt;code&gt;/animal-facts&lt;/code&gt; endpoint with the method &lt;code&gt;ListAnimalFacts()&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
    &lt;span class="s"&gt;"net/http"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;ZooHTTPClient&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;baseURL&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Client&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// Serialization of error response from zoo API service&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;ErrorResponse&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;StatusCode&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;    &lt;span class="s"&gt;`json:"status_code"`&lt;/span&gt;
    &lt;span class="n"&gt;Message&lt;/span&gt;    &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`json:"message"`&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ErrorResponse&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"got %d error: %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusCode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;AnimalFactsQuery&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;AnimalName&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="n"&gt;PageToken&lt;/span&gt;  &lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ZooHTTPClient&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;ListAnimalFacts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt; &lt;span class="n"&gt;AnimalFactsQuery&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;AnimalFactsResponse&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// HTTP implementation here; returns an&lt;/span&gt;
    &lt;span class="c"&gt;// AnimalFactsResponse if the HTTP request succeeds,&lt;/span&gt;
    &lt;span class="c"&gt;// or an error, of type ErrorResponse, if the request&lt;/span&gt;
    &lt;span class="c"&gt;// gets a non-2xx HTTP status code.&lt;/span&gt;

    &lt;span class="c"&gt;// returning nil, nil just so the code compiles&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;AnimalFactsResponse&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Facts&lt;/span&gt;         &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`json:"facts"`&lt;/span&gt;
    &lt;span class="n"&gt;AreThereMore&lt;/span&gt;  &lt;span class="kt"&gt;bool&lt;/span&gt;     &lt;span class="s"&gt;`json:"are_there_more"`&lt;/span&gt;
    &lt;span class="n"&gt;NextPageToken&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;   &lt;span class="s"&gt;`json:"next_page_token"`&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And here is the code we want to test, which we'll copy to a file like &lt;code&gt;main.go&lt;/code&gt;. In that code we pass the API client into &lt;code&gt;getSlothsFavoriteSnack&lt;/code&gt; so we know what snack to donate a whole bunch of to the zoo. The function returns that snack as a string on success, or if that's not mentioned in any of the facts from the API, then we return &lt;code&gt;errFactNotFound&lt;/code&gt; and dust off that library card in order to find that information.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ NOTE: There is a bug in this code. Don't spend a bunch of time looking for it now, though, we'll fix it when we find that bug using our tests!&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"errors"&lt;/span&gt;
    &lt;span class="s"&gt;"regexp"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;errFactNotFound&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"fact not found"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;favSnackMatcher&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;regexp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MustCompile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"favorite snack is (.*)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;getSlothsFavoriteSnack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ZooHTTPClient&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// Until we're at the last page of facts, call ListAnimalFacts&lt;/span&gt;
    &lt;span class="c"&gt;// with the current page token to paginate through the list,&lt;/span&gt;
    &lt;span class="c"&gt;// exiting when either the response's AreThereMore field is&lt;/span&gt;
    &lt;span class="c"&gt;// false, or we find out what sloths' favorite snack is.&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;pageToken&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ListAnimalFacts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AnimalFactsQuery&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;AnimalName&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"sloth"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;PageToken&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="n"&gt;pageToken&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c"&gt;// check if any facts match the "favorite snack is"&lt;/span&gt;
        &lt;span class="c"&gt;// regex and if so, return the match&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Facts&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;match&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;favSnackMatcher&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FindStringSubmatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;continue&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c"&gt;// check the response to see if there are any more&lt;/span&gt;
        &lt;span class="c"&gt;// pages of facts about sloths&lt;/span&gt;
        &lt;span class="n"&gt;pageToken&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NextPageToken&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// otherwise if the fact about sloths' favorite snack&lt;/span&gt;
    &lt;span class="c"&gt;// isn't in the zoo API, return errFactNotFound.&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;errFactNotFound&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since &lt;code&gt;ListAnimalFacts&lt;/code&gt; talks to the server for the zoo's API, the code is nondeterministic. So testing it in a repeatable way is a great use case for Testify Mock.&lt;/p&gt;

&lt;h2&gt;
  
  
  🥸 Basic test with mock
&lt;/h2&gt;

&lt;p&gt;If you recall from the last tutorial, the steps to doing a test with Testify Mock are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Take the nondeterministic piece of functionality and wrap it in a Go interface type.&lt;/li&gt;
&lt;li&gt;Write an implementation of the interface that uses Testify Mock.&lt;/li&gt;
&lt;li&gt;In the tests, use the mock implementation to select deterministic results of the functions your interface calls.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So to start, let's make an interface for our API client.&lt;/p&gt;

&lt;h3&gt;
  
  
  Wrapping our client in an interface
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;ZooClient&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;ListAnimalFacts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt; &lt;span class="n"&gt;AnimalFactsQuery&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;AnimalFactsResponse&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we had additional client methods used in our code, such as for other endpoints on the API, we would also add those methods to the &lt;code&gt;ZooClient&lt;/code&gt; type as well, but for this tutorial we're only testing code that uses &lt;code&gt;ListAnimalFacts&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now, to enable using a mock in &lt;code&gt;getSlothsFavoriteSnack&lt;/code&gt;, we change that function's signature to take in a ZooClient rather than a *ZooHTTPClient.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gd"&gt;- func getSlothsFavoriteSnack(c *ZooHTTPClient) (string, error) {
&lt;/span&gt;&lt;span class="gi"&gt;+ func getSlothsFavoriteSnack(c ZooClient) (string, error) {
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Writing a mock implementation of our client
&lt;/h3&gt;

&lt;p&gt;And now just like with the random number generator in the last tutorial, we can use the &lt;code&gt;mock.Mock&lt;/code&gt; type to write a mock implementation of our client.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"github.com/stretchr/testify/mock"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;mockClient&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;mock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Mock&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;newMockClient&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;mockClient&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;mockClient&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;mockClient&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;ListAnimalFacts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;q&lt;/span&gt; &lt;span class="n"&gt;AnimalFactsQuery&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;AnimalFactsResponse&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Called&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;AnimalFactsResponse&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Just like in the last tutorial, we start by making a mock client that embeds a &lt;code&gt;mock.Mock&lt;/code&gt; object, and we retrieve the return values we assigned to the passed-in parameters using &lt;code&gt;Mock.Called&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Unlike in the random number generator example, though, the object we're returning is an &lt;code&gt;*AnimalFactsResponse&lt;/code&gt; rather than a primitive Go type like an int. So to get our response as the type we want, we call &lt;code&gt;args.Get(0)&lt;/code&gt; which returns an &lt;code&gt;interface{}/any&lt;/code&gt; that we then can convert to the type we want with &lt;code&gt;.(*AnimalFactsResponse)&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using our client in a test
&lt;/h3&gt;

&lt;p&gt;Now, let's use our client in a test!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"testing"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;firstPageAPIReq&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AnimalFactsQuery&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;AnimalName&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"sloth"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;PageToken&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;TestGetSlothsFavoriteSnack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;newMockClient&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;On&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="s"&gt;"ListAnimalFacts"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;firstPageAPIReq&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;AnimalFactsResponse&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Facts&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="s"&gt;"Sloths' slowness is actually used as a form of camouflage"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;"Baby sloths make the cutest li'l squeak 🥰"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;"Sloths' favorite snack is hibiscus flowers"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;AreThereMore&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;NextPageToken&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;favSnack&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;getSlothsFavoriteSnack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatalf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"got error getting sloths' favorite snack: %v"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;favSnack&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="s"&gt;"hibiscus flowers"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="s"&gt;"expected favorite snack to be hibiscus flowers, got %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;favSnack&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First, we pass in the AnimalFactsQuery we're going to use to &lt;code&gt;c.On()&lt;/code&gt; and assign it a mock API response with &lt;code&gt;c.Return()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now our mock client is ready to use; we call &lt;code&gt;getSlothsFavoriteSnack&lt;/code&gt;, and it uses our mock client; when it calls &lt;code&gt;ZooClient.ListAnimalFacts&lt;/code&gt;, it gets back our API response, loops through the &lt;code&gt;Facts&lt;/code&gt; in the API response, and when it reaches the one titled &lt;em&gt;Sloths' favorite snack is hibiscus flowers&lt;/em&gt;, that matches the regular expression, so getSlothsFavoriteSnack returns &lt;code&gt;"hibiscus flowers", nil&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Finally, back in our test, we verify that &lt;code&gt;favSnack&lt;/code&gt; is hibiscus flowers and &lt;code&gt;err&lt;/code&gt; is nil, just like we would if this test was using a client pointed at and authenticated to a real zoo API.&lt;/p&gt;

&lt;p&gt;Run the test, and you'll see that it passed and that sloths love hibiscus flowers! 🌺 &lt;/p&gt;

&lt;p&gt;Just like that, we've got a Go test on &lt;strong&gt;what happens when our code gets back a certain response from an API&lt;/strong&gt;, and we can run it any time we want with the same result from our mock API; if the zoo's real API server is down, then this test will still run successfully since we're not talking to the real API!&lt;/p&gt;

&lt;p&gt;Speaking of when the server is down, we don't want to test &lt;em&gt;just&lt;/em&gt; the happy path; we should have some test coverage for what happens if we get an error calling &lt;code&gt;getSlothsFavoriteSnack&lt;/code&gt; too.&lt;/p&gt;

&lt;h2&gt;
  
  
  ⛔️ Handling error cases
&lt;/h2&gt;

&lt;p&gt;There's a couple error cases from the API we should have test coverage for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The server is giving back 500's, which as I mentioned at the beginning of this post, is hard to re-create with a real API.&lt;/li&gt;
&lt;li&gt;The API doesn't have the animal fact we want.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Testing that our code handles internal server errors correctly
&lt;/h3&gt;

&lt;p&gt;Let's start with testing the 500 internal server error case.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;TestGetSlothsFavoriteSnack500Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;newMockClient&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;On&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ListAnimalFacts"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;firstPageAPIReq&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;AnimalFactsResponse&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;ErrorResponse&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;StatusCode&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;Message&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"server error"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;getSlothsFavoriteSnack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"got nil error from getSlothsFavoriteSnack"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;errRes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ErrorResponse&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatalf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"expected error to be ErrorResponse, got %T"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;errRes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusCode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="m"&gt;500&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"expected 500, got %d status code"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Like before, we set up a mock response for &lt;code&gt;firstPageAPIReq&lt;/code&gt; in &lt;code&gt;c.On().Return()&lt;/code&gt;. But this time, rather than passing in a successful response, we pass in a nil &lt;code&gt;AnimalFactsResponse&lt;/code&gt; and an &lt;code&gt;ErrorResponse&lt;/code&gt; as our error.&lt;/p&gt;

&lt;p&gt;Then, we call &lt;code&gt;getSlothsFavoriteSnack&lt;/code&gt; and validate that we got an error, it's of type &lt;code&gt;ErrorResponse&lt;/code&gt;, and that its status code is 500. So when we run the test, once again it passes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Testing the error case where the API doesn't have the sloth fact we want
&lt;/h3&gt;

&lt;p&gt;Now that we've got a test for our 500 error, let's test the case where we don't have the sloth fact we want. In that case we expect that &lt;code&gt;getSlothsFavoriteSnack&lt;/code&gt; returns &lt;code&gt;errFactNotFound&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;TestGetSlothsFavoriteSnackNotFound&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;newMockClient&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;On&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="s"&gt;"ListAnimalFacts"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;firstPageAPIReq&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;AnimalFactsResponse&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Facts&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="s"&gt;"Sloths' slowness is actually used as a form of camouflage"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;"Baby sloths make the cutest li'l squeak 🥰"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;"Sloths need their beauty sleep, plz send noise-cancelling headphones"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;AreThereMore&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;NextPageToken&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;getSlothsFavoriteSnack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;errFactNotFound&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatalf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"should have gotten errFactNotFound, got %v"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We start with a similar test setup to the success case, except this time around, the response we set up doesn't include information about what sloths like to eat. So at the bottom of the test, we assert that the error we get back is &lt;code&gt;errFactNotFound&lt;/code&gt; and that we should head to the library.&lt;/p&gt;

&lt;p&gt;Run this test though, and you should get an infinite loop; if you wait about 10 minutes the test will fail because &lt;code&gt;getSlothsFavoriteSnack&lt;/code&gt; never returns, so the test times out.&lt;/p&gt;

&lt;p&gt;In other words, we found a bug in &lt;code&gt;getSlothsFavoriteSnack&lt;/code&gt;. If you recall, this was the for loop in there:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ListAnimalFacts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AnimalFactQuery&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;AnimalName&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"sloth"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;PageToken&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="n"&gt;pageToken&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Facts&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;match&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;favSnackMatcher&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FindStringSubmatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;continue&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;pageToken&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NextPageToken&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We use a for loop because this API is paginated so that if there's more than one page worth of sloth facts, we can check the next page. The bug is that we never &lt;code&gt;break&lt;/code&gt; out of the for loop if we're at the end of the list of sloth facts, as specified by the &lt;code&gt;AreThereMore&lt;/code&gt; field on the response. If you've tricked out your editor, that might have told you that the line returning &lt;code&gt;errFactNotFound&lt;/code&gt; was unreachable, and that's why.&lt;/p&gt;

&lt;p&gt;So let's fix the bug!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;    for _, f := range res.Facts {
        match := favSnackMatcher.FindStringSubmatch(f)
        if len(match) &amp;lt; 2 {
            continue
        }
        return match[1], nil
    }

    pageToken = res.NextPageToken
&lt;span class="gi"&gt;+   if !res.AreThereMore {
+       break 
+   }
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the test again and now our test should pass!&lt;/p&gt;

&lt;h2&gt;
  
  
  📖 Pagination with MatchedBy, Once, and AssertNumberOfCalls
&lt;/h2&gt;

&lt;p&gt;As one last thing to test, since the API is paginated, we also should have some test coverage for when the information about sloths' favorite snack isn't on page 1.&lt;/p&gt;

&lt;p&gt;In this API we're mocking, requests and responses include a &lt;code&gt;PageToken/NextPageToken&lt;/code&gt; field, to tell the API which page of sloth facts to retrieve. So a test for the scenario where the search results are on the second page might look like this pseudocode:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add a mock for page 1, where the AnimalName is "sloth" and PageToken is a blank string.

&lt;ol&gt;
&lt;li&gt;Have that mock API call return our search results, &lt;code&gt;AreThereMore=true&lt;/code&gt;, and &lt;code&gt;NextPageToken=NEXT&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;
&lt;li&gt;Add a mock for page 2, where AnimalName is "sloth" and PageToken is "NEXT".

&lt;ol&gt;
&lt;li&gt;Have that mock API call return a second page of search results; &lt;code&gt;AreThereMore=false&lt;/code&gt; and page 2 contains the information that sloths love hibiscus flowers.&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;getSlothsFavoriteSnack&lt;/code&gt; and check that "hibiscus flowers" is still retrieved.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We could pass each individual query into &lt;code&gt;Mock.On()&lt;/code&gt;, and that wouldn't be too difficult to write in this example code. However, if this API was more complicated and we were testing more-complicated fields, it can be a pain to ensure that each call to &lt;code&gt;Mock.On&lt;/code&gt; has &lt;em&gt;exactly&lt;/em&gt; the right fields on the structs we're passing in. In particular, you might have a more complicated function than &lt;code&gt;getSlothsFavoriteSnack&lt;/code&gt; you want to test, where it takes a lot of staring at your code in order to figure out the exact arguments each individual API call has.&lt;/p&gt;

&lt;p&gt;In this test we're running, we're not that worried about the exact content of the &lt;code&gt;PageToken&lt;/code&gt; field, since API page tokens tend to be pretty opaque. Whether the page token says something like "page 2", "some more facts on the next page", or a UUID. Essentially, we're not the ones who care about the page token's formst; the zoo's API team is in charge of that!&lt;/p&gt;

&lt;p&gt;What we're really testing in a &lt;code&gt;TestGetSlothsFavoriteSnackResultIsOnTheSecondPage&lt;/code&gt; (that's a mouthful!) test is that &lt;strong&gt;if the information we want is on the second page, we're still able to retrieve it with another query for sloth facts&lt;/strong&gt;. And there's a handful of functions that can help us test that, to a reasonable "just the important stuff" level of detail, which are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://pkg.go.dev/github.com/stretchr/testify/mock#MatchedBy"&gt;MatchedBy&lt;/a&gt;; instead of passing in an argument to &lt;code&gt;Mock.On()&lt;/code&gt; that the argument in the test has to &lt;em&gt;exactly match&lt;/em&gt;, you pass in a function that defines the criteria for whether an argument in the test matches the argument to &lt;code&gt;Mock.On()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://pkg.go.dev/github.com/stretchr/testify/mock#Call.Once"&gt;Once&lt;/a&gt;; specify arguments and return values with &lt;code&gt;Mock.On().Return()&lt;/code&gt; that are only to be called and given back once. For example in a paginated API, the arguments you call in each round of the loop are nearly the same, so you can add &lt;code&gt;Once()&lt;/code&gt; on to your mock call to say "give us back each page of results only once".&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://pkg.go.dev/github.com/stretchr/testify/mock#Mock.AssertNumberOfCalls"&gt;AssertNumberOfCalls&lt;/a&gt;; if the mocked-out code you're testing is called in a loop, this allows us to check that the loop ran the expected number of times.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To try these out, let's give some test coverage where sloths' favorite snack is on page 2.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;reqSlothFacts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt; &lt;span class="n"&gt;AnimalFactsQuery&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="n"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ToLower&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AnimalName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;"sloth"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"lemur: caffeine-free edition"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"descendants of the giants who made today's avocados happen"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
    &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;page1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AnimalFactsResponse&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Facts&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="s"&gt;"Sloths' slowness is actually used as a form of camouflage"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"Baby sloths make the cutest li'l squeak 🥰"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"Sloths need their beauty sleep, plz send noise-cancelling headphones"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="n"&gt;AreThereMore&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;NextPageToken&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"some more facts on the next page"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;page2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AnimalFactsResponse&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Facts&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"Sloths' favorite snack is hibiscus flowers"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;TestGetSlothsFavoriteSnackOnPage2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;newMockClient&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;On&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ListAnimalFacts"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MatchedBy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reqSlothFacts&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
        &lt;span class="n"&gt;Return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;page1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
        &lt;span class="n"&gt;Once&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;On&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ListAnimalFacts"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MatchedBy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reqSlothFacts&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
        &lt;span class="n"&gt;Return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;page2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
        &lt;span class="n"&gt;Once&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;favSnack&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;getSlothsFavoriteSnack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatalf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"got error getting sloths' favorite snack: %v"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;favSnack&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="s"&gt;"hibiscus flowers"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="s"&gt;"expected favorite snack to be hibiscus flowers, got %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;favSnack&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AssertNumberOfCalls&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"ListAnimalFacts"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's what happens in our test:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Outside of our test, we define the function &lt;code&gt;reqSlothFacts&lt;/code&gt; we'll pass into &lt;code&gt;MatchedBy&lt;/code&gt;. We match the word "sloth", as well as a couple other ways to describe a sloth just for fun: "lemur: caffeine-free edition" and "descendants of the giants who made today's avocados happen" (&lt;a href="https://en.wikipedia.org/wiki/Megatherium"&gt;giant ground sloths&lt;/a&gt; 10,000 years ago ate what avocados looked like 10,000 years ago, so next time you have some guac, thank a sloth). We also define two pages of search results.&lt;/li&gt;
&lt;li&gt;Inside our &lt;code&gt;TestGetSlothsFavoriteSnackOnPage2&lt;/code&gt;, we define two calls to &lt;code&gt;ListAnimalFacts&lt;/code&gt; similar to before, but this time instead of passing in an exact query, we pass in &lt;code&gt;mock.MatchedBy(reqSlothFacts)&lt;/code&gt; to say &lt;strong&gt;"a call to ListAnimalFacts matches this call to &lt;code&gt;Mock.On()&lt;/code&gt; if its argument, passed into &lt;code&gt;reqSlothFacts&lt;/code&gt;, returns true"&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;On each call to &lt;code&gt;Mock.On()&lt;/code&gt;, we add on a call to &lt;code&gt;.Once()&lt;/code&gt;. When we call &lt;code&gt;getSlothsFavoriteSnack&lt;/code&gt;, the first time we get back the results we defined with &lt;code&gt;page1&lt;/code&gt; and the second time we get back the results we defined with &lt;code&gt;page2&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Then we run the test the same way as before, but at the tail end, we run &lt;code&gt;AssertNumberOfCalls&lt;/code&gt; to show that we really did call &lt;code&gt;ListAnimalFacts&lt;/code&gt; twice, rather than getting the results on the first page.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;By the way, in addition to &lt;code&gt;MatchedBy&lt;/code&gt;, if you don't need such fine-grained control over the arguments you pass in, there also is &lt;a href="https://pkg.go.dev/github.com/stretchr/testify/mock#pkg-constants"&gt;mock.Anything&lt;/a&gt; that you can pass into &lt;code&gt;Mock.On&lt;/code&gt; to match any argument at all.&lt;/p&gt;

&lt;p&gt;For example, a lot of API clients these days take in a &lt;code&gt;context.Context&lt;/code&gt;, which is often in charge of things like traces with observability tools or giving a request a deadline to finish with &lt;code&gt;context.WithDeadline&lt;/code&gt;. But often that does not affect the headers and body of our request or response. So if the context isn't a focal point of what you're testing, you can mock it out with &lt;code&gt;Anything&lt;/code&gt;. For example if our client's interface looked like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;ZooClient&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;ListAnimalFacts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;q&lt;/span&gt; &lt;span class="n"&gt;AnimalFactsQuery&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;AnimalFactsResponse&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You would do your &lt;code&gt;Mock.On&lt;/code&gt; call like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;  c := newMockClient()
  c.On(
      "ListAnimalFacts",
&lt;span class="gi"&gt;+     mock.Anything,
&lt;/span&gt;      firstPageAPIReq,
  ).Return(&amp;amp;AnimalFactsResponse{
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  🧰 Testify Mock is just one tool for testing your web apps
&lt;/h2&gt;

&lt;p&gt;As you can see, Testify Mock is a convenient tool for testing code that needs to make an API call, particularly when it comes to HTTP responses like 500 errors that you're not suppposed to consistently be getting.&lt;/p&gt;

&lt;p&gt;But there's another way we could have tested all these API interactions without having to rely on the real API:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Make an &lt;code&gt;httptest.Server&lt;/code&gt; that has HTTP handlers to mimic the API endpoints we're testing, deserializing requests and serializing responses&lt;/li&gt;
&lt;li&gt;Point the &lt;em&gt;HTTP&lt;/em&gt; implementation of the API client at that server and run tests using that implementation&lt;/li&gt;
&lt;li&gt;Do assertions on the mock responses you get back&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Both the httptest approach and Testify Mock approach are valid ways to test the code. Furthermore, while both kinds of mocks are useful themselves, that's not to say testing against the real API isn't itself beneficial. By testing against the very same servers your code talks to in production, you can sniff out server behaviors your dev team wasn't aware of from just reading the server's API documentation. While this isn't a hard and fast rule, my personal style for when to use which kind of Go test is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When I'm the one implementing the client to the API I'm working with, I would go with the &lt;strong&gt;httptest Server&lt;/strong&gt; approach for its unit tests. Part of the client's job is to serialize and deserialize Go types, so the thing being tested, so the focal point of the test is that &lt;strong&gt;the headers, request, and response bodies are correct&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;For code that's built on top of a client, such as &lt;code&gt;getSlothsFavoriteSnack&lt;/code&gt;, my go-to is Testify Mock. Either I wrote and unit-tested the HTTP implementation of the client or the open source developer I'm &lt;code&gt;go getting&lt;/code&gt; the client from did. So now the focal point of a test is the question &lt;strong&gt;"given that the API client works as expected, does my code do the right thing with the response it gets back"&lt;/strong&gt;?

&lt;ul&gt;
&lt;li&gt;However if you got the client as a dependency but it doesn't have test coverage for the API calls you're making, it might still be a good idea to test using the &lt;code&gt;httptest.Server&lt;/code&gt; approach if its implementation allows you to point it at a custom httptest Server URL.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Finally, for testing that your app works end-to-end, having your continuous integration platform run a &lt;strong&gt;nightly build&lt;/strong&gt; that runs tests against the real API will help you detect bugs and unexpected behaviors your mocks might not have taken into account.

&lt;ul&gt;
&lt;li&gt;⚠️WARNING⚠️: Chances are, the server you're talking to in this nightly build will need to obtain and use some kind of API key or authentication token. BE CAREFUL configuring your continuous integration so that that authentication doesn't get stolen. In particular, do not put the key/token directly in your code.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Happy testing!&lt;/p&gt;

</description>
      <category>go</category>
      <category>testing</category>
      <category>webdev</category>
      <category>codenewbie</category>
    </item>
    <item>
      <title>Mocks in Go tests with Testify Mock</title>
      <dc:creator>Andy Haskell</dc:creator>
      <pubDate>Mon, 24 Oct 2022 14:07:47 +0000</pubDate>
      <link>https://dev.to/salesforceeng/mocks-in-go-tests-with-testify-mock-6pd</link>
      <guid>https://dev.to/salesforceeng/mocks-in-go-tests-with-testify-mock-6pd</guid>
      <description>&lt;p&gt;In parts 1-3 of this tutorial series, we saw how you can use Go to write automated tests. Go's testing is very conducive to giving test coverage to a lot of your codebase's functionality. However, there's one area in particular where it's harder to do automated tests: code that is &lt;strong&gt;nondeterministic&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;When I say nondeterministic code, I am talking about code where &lt;strong&gt;you don't have total control&lt;/strong&gt; over the code's logic and output. This can be things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🧮 Code that uses pseudorandom number generators, like &lt;code&gt;math/rand&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;💻 Web API calls and their response payloads, or errors&lt;/li&gt;
&lt;li&gt;⏰ The current time returned by &lt;code&gt;time.Now&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Luckily, one tool that helps with testing nondeterministic code, is the &lt;code&gt;mock&lt;/code&gt; package of the popular &lt;a href="//github.com/stretchr/testify"&gt;Testify testing framework&lt;/a&gt;, which you can use for mocking out these API calls.&lt;/p&gt;

&lt;p&gt;For this tutorial, we'll look at how to mock out code that uses &lt;code&gt;math/rand&lt;/code&gt;, then in a follow-up post, we'll mock out a fake web API client to see how to use Testify Mock in more complex scenarios.&lt;/p&gt;

&lt;p&gt;Prerequisites for this tutorial are familiarity with the basics of writing and running a Go test, which the &lt;a href="https://dev.to/salesforceeng/intro-to-automated-testing-in-go-4mjl"&gt;first tutorial&lt;/a&gt; in this series covers.&lt;/p&gt;

&lt;h2&gt;
  
  
  🎰 Getting some nondeterministic code and the Testify Mock package
&lt;/h2&gt;

&lt;p&gt;Probably the easiest nondeterministic code to get ahold of is the &lt;code&gt;math/rand&lt;/code&gt; package, so for this tutorial, we'll look at how we would use Testify Mock to test code that uses randomness. We'll make a function that takes in an integer, and integer-divides (no decimal point) it by a number between 1 and 10.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"math/rand"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;divByRand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;numerator&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;numerator&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rand&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Intn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pretty simple function, but since we called &lt;code&gt;rand.Intn&lt;/code&gt;, which takes in a maximum value and returns a random integer up to that maximum, &lt;code&gt;divByRand&lt;/code&gt; as a whole is nondeterministic; we have control over the numerator, but not the denominator.&lt;/p&gt;

&lt;p&gt;But that's where Testify Mock package comes in; we can make it so in a given test, we &lt;em&gt;do&lt;/em&gt; get back the same value for &lt;code&gt;rand.Intn&lt;/code&gt; every time.&lt;/p&gt;

&lt;p&gt;First let's install Testify Mock with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;go get github.com/stretchr/testify/mock
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we're ready to use Testify Mock to give &lt;code&gt;divByRand&lt;/code&gt; some test coverage!&lt;/p&gt;

&lt;h2&gt;
  
  
  ✨ Using Testify Mock
&lt;/h2&gt;

&lt;p&gt;Now that we've got our nondeterministic code, here's the steps to making it testable with Testify Mock:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Take the nondeterministic piece of functionality and wrap it in a Go interface type.&lt;/li&gt;
&lt;li&gt;Write an implementation of the interface that uses Testify Mock.&lt;/li&gt;
&lt;li&gt;In the tests, use the mock implementation to select deterministic results of the functions your interface calls.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Besides injecting your mock into your code, the test is otherwise written like any other Go test.&lt;/p&gt;

&lt;p&gt;Let's try it out on &lt;code&gt;divByRand&lt;/code&gt;, step by step!&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Take the nondeterministic function calls and wrap them in an interface
&lt;/h3&gt;

&lt;p&gt;For &lt;code&gt;divByRand&lt;/code&gt;, the nondeterministic code we're working with is &lt;code&gt;math/rand&lt;/code&gt;'s &lt;code&gt;Intn&lt;/code&gt; function, which takes in an integer and returns another integer. Here's what wrapping that method in an interface looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;randNumberGenerator&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;randomInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that we've got our interface, here's the plain implementation that calls the standard library's &lt;code&gt;rand.Intn&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// our standard-library implementation is an empty&lt;/span&gt;
&lt;span class="c"&gt;// struct whose randomInt method calls math/rand.Intn&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;standardRand&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="n"&gt;standardRand&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;randomInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;rand&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Intn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that we've got one interface implementation, we can use that in our &lt;code&gt;divByRand&lt;/code&gt; function like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;  func divByRand(
      numerator int,
&lt;span class="gi"&gt;+     r randNumberGenerator,
&lt;/span&gt;  ) int {
&lt;span class="gd"&gt;-     return numerator / rand.Intn(10) 
&lt;/span&gt;&lt;span class="gi"&gt;+     return numerator / r.randomInt(10)
&lt;/span&gt;  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We now would call divByRandom in our production code using a function call like &lt;code&gt;divByRandom(200, standardRand{})&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In tests, though, we will instead use a mock implementation of our &lt;code&gt;randNumberGenerator&lt;/code&gt; interface, which we'll write in the next section.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Write an implementation of the interface that uses Testify Mock
&lt;/h3&gt;

&lt;p&gt;The Testify Mock package's main type is &lt;code&gt;Mock&lt;/code&gt;, which handles the logic for mock API calls, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For each method being mocked, keeping track of how many times it was called, and with what arguments.&lt;/li&gt;
&lt;li&gt;Providing the coder with a way to specify return values to get back from the mock implementation when specified arguments are passed into given function calls.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We would first set up our mock implementation by embedding a Mock into a struct:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;mockRand&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;mock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Mock&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;newMockRand&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;mockRand&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;mockRand&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By embedding a &lt;code&gt;Mock&lt;/code&gt;, now the &lt;code&gt;mockRand&lt;/code&gt; type has the methods for registering an API call that you expect to happen in the tests.&lt;/p&gt;

&lt;p&gt;For example, at the beginning of a test that uses the &lt;code&gt;randomNumberGenerator&lt;/code&gt; interface, we could call:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="n"&gt;mockRand&lt;/span&gt;
&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;On&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"randomInt"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;6&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;which says "if the number 10 is passed in as the maximum number for this &lt;code&gt;mockRand&lt;/code&gt;'s &lt;code&gt;randomInt&lt;/code&gt; method, then always return the number 6".&lt;/p&gt;

&lt;p&gt;In order to be able to use &lt;code&gt;m.On("randomInt", arg)&lt;/code&gt; however, we will need to actually give our &lt;code&gt;mockRand&lt;/code&gt; a &lt;code&gt;randomInt&lt;/code&gt; method. Here's how we would do that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;mockRand&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;randomInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Called&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We've got two lines of code, let's take a look at what they do. If it seems confusing at first, no worries; it will make more sense when we are actually using this code in a test.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In the first line when &lt;code&gt;randomInt&lt;/code&gt; is called, we call &lt;a href="https://pkg.go.dev/github.com/stretchr/testify/mock#Mock.Called"&gt;Mock.Called&lt;/a&gt; to record that it was called with the value passed in for &lt;code&gt;max&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Additionally, &lt;code&gt;m.Called&lt;/code&gt; returns an &lt;a href="https://pkg.go.dev/github.com/stretchr/testify/mock#Arguments"&gt;Arguments&lt;/a&gt; object, which contains the return value(s) that we specified in the test to be returned if the function gets the given value of &lt;code&gt;max&lt;/code&gt;. For example, if we called &lt;code&gt;m.On("randomInt", 20).Return(7)&lt;/code&gt; in the test, &lt;code&gt;m.Called(20)&lt;/code&gt; would return an &lt;code&gt;Arguments&lt;/code&gt; object holding the return value 7.&lt;/li&gt;
&lt;li&gt;Finally, to retrieve the return value, in the second line we call &lt;code&gt;args.Int(0)&lt;/code&gt;, which means "return the zeroeth return value, and it will be of type int".&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Note that in addition to &lt;a href="https://pkg.go.dev/github.com/stretchr/testify/mock#Arguments.Int"&gt;Arguments.Int&lt;/a&gt;, there's also &lt;a href="https://pkg.go.dev/github.com/stretchr/testify/mock#Arguments.Bool"&gt;Bool&lt;/a&gt;, &lt;a href="https://pkg.go.dev/github.com/stretchr/testify/mock#Arguments.String"&gt;String&lt;/a&gt;, and &lt;a href="https://pkg.go.dev/github.com/stretchr/testify/mock#Arguments.Error"&gt;Error&lt;/a&gt; methods, which give us back the n-th return value in those types. And if you have a return value of another type, you would retrieve it with the &lt;a href="https://pkg.go.dev/github.com/stretchr/testify/mock#Arguments.Bool"&gt;Arguments.Get&lt;/a&gt; method, which returns an &lt;code&gt;interface{}&lt;/code&gt; you would then convert to the type you expect to get back.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. In the tests, use the mock implementation and feed in results the function returns.
&lt;/h3&gt;

&lt;p&gt;We've got our &lt;code&gt;mockRand&lt;/code&gt; type implementing the &lt;code&gt;randomNumberGenerator&lt;/code&gt; interface, so it can be passed into &lt;code&gt;divByRand&lt;/code&gt; in Go code, including in our tests. The steps of our test now are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create an instance of your mock interface implementation.&lt;/li&gt;
&lt;li&gt;Specify what results you want back when the mock's methods are called with a given set of arguments using the &lt;a href="https://pkg.go.dev/github.com/stretchr/testify/mock#Mock.On"&gt;On&lt;/a&gt; and &lt;a href="https://pkg.go.dev/github.com/stretchr/testify/mock#Call.Return"&gt;Return&lt;/a&gt; methods.&lt;/li&gt;
&lt;li&gt;Run the code that's being tested, the standard way you would in a Go test.&lt;/li&gt;
&lt;li&gt;Optionally, use methods like &lt;a href="https://pkg.go.dev/github.com/stretchr/testify/mock#Mock.AssertCalled"&gt;Mock.AssertCalled&lt;/a&gt; to check that a given method indeed had been called during the test.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here's what that looks like in code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"testing"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;TestDivByRand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// get our mockRand&lt;/span&gt;
    &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;newMockRand&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="c"&gt;// specify our return value. Since the code in divByRand&lt;/span&gt;
    &lt;span class="c"&gt;// passes 10 into randomInt, we pass 10 in as the argument&lt;/span&gt;
    &lt;span class="c"&gt;// to go with randomInt, and specify that we want the&lt;/span&gt;
    &lt;span class="c"&gt;// method to return 6.&lt;/span&gt;
    &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;On&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"randomInt"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;6&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// now run divByRand and assert that we got back the&lt;/span&gt;
    &lt;span class="c"&gt;// return value we expected, just like in a Go test that&lt;/span&gt;
    &lt;span class="c"&gt;// doesn't use Testify Mock.&lt;/span&gt;
    &lt;span class="n"&gt;quotient&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;divByRand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;quotient&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"expected quotient to be 5, got %d"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;quotient&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// check that randomInt was called with the number 10;&lt;/span&gt;
    &lt;span class="c"&gt;// if not then the test fails&lt;/span&gt;
    &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AssertCalled&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"randomInt"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run &lt;code&gt;go test -v&lt;/code&gt; and you'll get a passing test. But there's a bug in the original implementation of &lt;code&gt;divByRand&lt;/code&gt;, so let's find it and give that bug some test coverage!&lt;/p&gt;

&lt;h2&gt;
  
  
  🐛 Finding and fixing a bug using Testify Mock
&lt;/h2&gt;

&lt;p&gt;We wrote a test that utilizes Testify Mock, so now let's try using it to find a bug!&lt;/p&gt;

&lt;p&gt;Since we're dividing by a nondeterministic value, we should have test coverage to make sure we can't accidentally divide by zero.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;TestDivByRandCantDivideByZero&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;newMockRand&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;On&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"randomInt"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="n"&gt;quotient&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;divByRand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;quotient&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="m"&gt;30&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"expected quotient to be 30, got %d"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;quotient&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This time around, when we pass 10 into our mockRand's randomInt method, we return 0. So in divByRand, we end up dividing by 0.&lt;/p&gt;

&lt;p&gt;Run &lt;code&gt;go test -v&lt;/code&gt; and you should get:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;--- FAIL: TestDivByRandCantDivideByZero (0.00s)
panic: runtime error: integer divide by zero [recovered]
    panic: runtime error: integer divide by zero
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A panic from dividing by zero. Let's fix &lt;code&gt;divByRand&lt;/code&gt; method to prevent this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;  func divByRand(n int, r randNumberGenerator) int {
&lt;span class="gd"&gt;-     return n / r.randomInt(10)
&lt;/span&gt;&lt;span class="gi"&gt;+     denominator := 1 + int(r.randomInt(10))
+     return n / denominator
&lt;/span&gt;  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that we're passing 9 instead of 10 into our call to &lt;code&gt;randomInt&lt;/code&gt;, we do need to update our test coverage to register a call to &lt;code&gt;randomInt(9)&lt;/code&gt; instead of &lt;code&gt;randomInt(10)&lt;/code&gt;, and for TestDivByRand, we need to return 5 instead of 6 since in divByRand we add 1 to the returned value.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;  func TestDivByRand(t *testing.T) {
      var m mockRand
&lt;span class="gd"&gt;-     m.On("randomInt", 10).Return(6)
&lt;/span&gt;&lt;span class="gi"&gt;+     m.On("randomInt", 10).Return(5)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run &lt;code&gt;go test -v&lt;/code&gt; one more time and you should get...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;=== RUN   TestDivByRand
--- PASS: TestDivByRand (0.00s)
=== RUN   TestDivByRandCantDivideByZero
--- PASS: TestDivByRandCantDivideByZero (0.00s)
PASS
ok      github.com/andyhaskell/testify-mock 0.114s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Passing tests!&lt;/p&gt;

&lt;p&gt;We've looked at how to use Testify Mock to write test coverage for randomness. In the next tutorial, we'll take a look at using Testify Mock to mock out a web API call.&lt;/p&gt;

</description>
      <category>go</category>
      <category>testing</category>
      <category>webdev</category>
      <category>codenewbie</category>
    </item>
    <item>
      <title>Test your Go web apps with httptest</title>
      <dc:creator>Andy Haskell</dc:creator>
      <pubDate>Fri, 23 Jul 2021 14:50:05 +0000</pubDate>
      <link>https://dev.to/salesforceeng/test-your-go-web-apps-with-httptest-26mc</link>
      <guid>https://dev.to/salesforceeng/test-your-go-web-apps-with-httptest-26mc</guid>
      <description>&lt;p&gt;In &lt;a href="https://dev.to/salesforceeng/intro-to-automated-testing-in-go-4mjl"&gt;part 1 of this series&lt;/a&gt;, we looked at the basics of writing tests in Go with the &lt;code&gt;testing.T&lt;/code&gt; type, and in &lt;a href="https://dev.to/salesforceeng/subtesting-skipping-and-cleanup-in-the-go-testing-t-49ea"&gt;part 2&lt;/a&gt;, we looked at how with just the &lt;code&gt;testing.T&lt;/code&gt; type, you can organize your tests with its &lt;code&gt;Run&lt;/code&gt;, &lt;code&gt;Skip&lt;/code&gt;, and &lt;code&gt;Cleanup&lt;/code&gt; methods. Even with a good grasp of just &lt;code&gt;testing.T&lt;/code&gt;, you're ready to write professional test coverage in your Go codebase.&lt;/p&gt;

&lt;p&gt;But &lt;code&gt;testing.T&lt;/code&gt; and isn't all that the Go standard library provides for writing Go tests! One of the most popular uses of Go is building the server code for web apps, using its detailed &lt;a href="https://golang.org/pkg/net/http/"&gt;net/http&lt;/a&gt; package. So the Go Team provided us with a sweet additional package for testing web apps in addition to the main &lt;code&gt;testing&lt;/code&gt; package: &lt;code&gt;net/http/httptest&lt;/code&gt;!&lt;/p&gt;

&lt;p&gt;In this tutorial we'll look at:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;📋 how to test an HTTP handler with httptest&lt;/li&gt;
&lt;li&gt;💻 how to use httptest to test against a real server&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This tutorial is for you if you're interested in Go web development or do webdev already, you're familiar with the basics of Go testing and structs, and you have some familiarity with the HTTP protocol's concepts of requests, responses, headers. If you've used the &lt;code&gt;net/http&lt;/code&gt; package, that will help you follow along, but if you're new to &lt;code&gt;net/http&lt;/code&gt;, this tutorial does have an overview of some Go web app concepts.&lt;/p&gt;

&lt;h2&gt;
  
  
  📶 A quick overview of Go HTTP handlers
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;If you already are familiar with Go HTTP handlers, feel free to read the code sample and then skip ahead to the next section. If you're new to Go web development or just want a recap, read on!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let's start with a recap of one of its core concepts: when you get an HTTP request, you process it using a &lt;strong&gt;handler&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Handlers look something like the &lt;code&gt;handleSlothfulMessage&lt;/code&gt; function in this code sample (if you're following along, save this to a file titled &lt;code&gt;server.go&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"net/http"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;handleSlothfulMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Header&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Content-Type"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"application/json"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;`{"message": "Stay slothful!"}`&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;appRouter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Handler&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;rt&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewServeMux&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;rt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandleFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/sloth"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;handleSlothfulMessage&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;rt&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ListenAndServe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;":1123"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;appRouter&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All Go HTTP handlers take in an implementation of the &lt;code&gt;ResponseWriter&lt;/code&gt; interface, and a &lt;code&gt;Request&lt;/code&gt; struct. Those objects have the following responsibilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;Request&lt;/code&gt; contains the data of the HTTP request that the HTTP client (ex a browser or cURL), sends to your web server, like:

&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;URL&lt;/strong&gt; that was requested, like the path and query parameters.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Request headers&lt;/strong&gt;, for example a &lt;code&gt;User-Agent&lt;/code&gt; header saying whether the request comes from Firefox, Chrome, a command-line client, or a punched card someone delivered to a card reader.&lt;/li&gt;
&lt;li&gt;The request &lt;strong&gt;body&lt;/strong&gt; for POST and PUT requests.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;ResponseWriter&lt;/code&gt; is in charge of formulating the HTTP response, so it handles things like:

&lt;ul&gt;
&lt;li&gt;Writing &lt;strong&gt;status codes&lt;/strong&gt;, like 200 for a successful request, or the familiar "404 file not found" websites make corny webpages for.&lt;/li&gt;
&lt;li&gt;Writing &lt;strong&gt;Response headers&lt;/strong&gt;, such as the &lt;code&gt;Content-Type&lt;/code&gt; to say what format our response is in, like HTML or JSON.&lt;/li&gt;
&lt;li&gt;Writing the response &lt;strong&gt;body&lt;/strong&gt;, which can be any response format, like an HTML webpage, a JSON object, or picture of a sloth 🌺!&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In our &lt;code&gt;handleSlothfulMessage&lt;/code&gt; function, we first add a header to indicate that our response is JSON with the line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Header&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Content-Type"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"application/json"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then we write out the bytes of a JSON message that has a header saying "Stay slothful!" with the line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;`{"message": "Stay slothful!"}`&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that because we didn't call &lt;code&gt;w.WriteHeader&lt;/code&gt; to explicitly select a status code for our HTTP response, the response's code will be 200/OK. If we had some kind of error scenario we'd need to handle in one of our web app's handlers, for example issues talking to a database, then in the handler function we might have code like this to give a 500/internal server error response:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;errorScenarioOccurs&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusInternalServerError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;`{"error_message": "description of the error"}`&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// rest of HTTP handler&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the &lt;code&gt;appRouter&lt;/code&gt; function, we make a router so requests to our &lt;code&gt;/sloth&lt;/code&gt; endpoint are handled with the &lt;code&gt;handleSlothfulMessage&lt;/code&gt; function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;appRouter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Handler&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;rt&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewServeMux&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;rt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandleFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/sloth"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;handleSlothfulMessage&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;rt&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, in the &lt;code&gt;main&lt;/code&gt; function, we start an HTTP server on port 1123 with &lt;code&gt;http.ListenAndServe&lt;/code&gt;, causing all requests to &lt;code&gt;localhost:1123&lt;/code&gt; to be handled by the HTTP router we made in &lt;code&gt;appRouter&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now if you start this Go program and then go to &lt;code&gt;localhost:1123/sloth&lt;/code&gt; in your browser or send a request to it via a client like cURL or Postman, you can see that we got back a simple JSON object!&lt;/p&gt;

&lt;h2&gt;
  
  
  📋 Testing your handler with httptest
&lt;/h2&gt;

&lt;p&gt;As you can see, you can start using your HTTP handler in a real web server without a lot of code. When you're running a &lt;code&gt;net/http&lt;/code&gt; server with &lt;code&gt;http.ListenAndServe&lt;/code&gt;, Go does the work behind the scenes for you of making &lt;code&gt;http.Request&lt;/code&gt; and &lt;code&gt;ResponseWriter&lt;/code&gt; objects when a request comes in from a client like your browser.&lt;/p&gt;

&lt;p&gt;But that does raise the question, where do we get a &lt;code&gt;ResponseWriter&lt;/code&gt; and &lt;code&gt;Request&lt;/code&gt; in our Go code when we're testing our HTTP handlers inside &lt;code&gt;go test&lt;/code&gt;?&lt;/p&gt;

&lt;p&gt;Luckily, the standard library has convenient code for testing that in the &lt;a href="https://golang.org/pkg/net/http/httptest/"&gt;net/http/httptest&lt;/a&gt; package to facilitate writing test coverage for that, with functions and types like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;NewRequest&lt;/code&gt; function for making the &lt;code&gt;*http.Request&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;a &lt;code&gt;ResponseRecorder&lt;/code&gt; type that both implements the &lt;code&gt;http.ResponseWriter&lt;/code&gt; interface and lets you replay the HTTP response.&lt;/li&gt;
&lt;li&gt;a &lt;code&gt;Server&lt;/code&gt; type for testing Go code that sends HTTP requests by setting up a &lt;strong&gt;real HTTP server&lt;/strong&gt; to send them to.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To see this httptest in action, let's see how we would test &lt;code&gt;handleSlothfulMessage&lt;/code&gt;. If you're following along, save this code to &lt;code&gt;server_test.go&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"net/http"&lt;/span&gt;
    &lt;span class="s"&gt;"net/http/httptest"&lt;/span&gt;
    &lt;span class="s"&gt;"strings"&lt;/span&gt;
    &lt;span class="s"&gt;"testing"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;TestHandleSlothfulMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;wr&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;httptest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewRecorder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;httptest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MethodGet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"/sloth"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;handleSlothfulMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;wr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;wr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Code&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusOK&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"got HTTP status code %d, expected 200"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;wr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Code&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;wr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="s"&gt;"Stay slothful!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="s"&gt;`response body "%s" does not contain "Stay slothful!"`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;wr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run &lt;code&gt;go test -v&lt;/code&gt;, and you should see a passing test!&lt;/p&gt;

&lt;p&gt;Let's take a look at what happened, and how we're using httptest in our code:&lt;/p&gt;

&lt;p&gt;First, there's making the ResponseWriter and Request:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;    &lt;span class="n"&gt;wr&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;httptest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewRecorder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;httptest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MethodGet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"/sloth"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We make our net/http &lt;code&gt;ResponseWriter&lt;/code&gt; implementation with &lt;code&gt;NewRecorder&lt;/code&gt;, and a &lt;code&gt;Request&lt;/code&gt; object pointed at our &lt;code&gt;/sloth&lt;/code&gt; endpoint using &lt;code&gt;NewRequest&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Then, we run our HTTP handler:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;handleSlothfulMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;wr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Remember that Go HTTP handler functions are just regular old Go functions that happen to take in specialized &lt;code&gt;net/http&lt;/code&gt; objects. That means we can run a handler without any actual HTTP server if we have a ResponseWriter and Request to pass into it. So we run our handler by passing &lt;code&gt;wr&lt;/code&gt; and &lt;code&gt;req&lt;/code&gt; into a call to our &lt;code&gt;handleSlothfulMessage&lt;/code&gt; function. Or if we wanted to test our web app's entire router rather than just one endpoint, we could even run &lt;code&gt;appRouter().ServeHTTP(wr, req)&lt;/code&gt;!&lt;/p&gt;

&lt;p&gt;Then, in the next piece of code, we check out the results of running &lt;code&gt;handleSlothfulMessage&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;wr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Code&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusOK&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"got HTTP status code %d, expected 200"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;wr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Code&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An httptest &lt;code&gt;ResponseRecorder&lt;/code&gt; implements the &lt;code&gt;ResponseWriter&lt;/code&gt; interface, but that's not all it gives us! It also has struct fields we can use for examining the response we get back from our HTTP request. One of them is &lt;code&gt;Code&lt;/code&gt;; we expect our response to be a 200, so we have an assertion comparing our status code to &lt;code&gt;http.StatusOK&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Additionally, a &lt;code&gt;ResponseRecorder&lt;/code&gt; makes it easy to look at the body of our response. It gives us a &lt;code&gt;bytes.Buffer&lt;/code&gt; field titled &lt;code&gt;Body&lt;/code&gt; that recorded the bytes of the response body. So we can test that our HTTP response contains the string "Stay slothful!", having our test fail if it does not.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;wr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="s"&gt;"Stay slothful!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="s"&gt;`response body "%s" does not contain "Stay slothful!"`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;wr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By the way, this technique also works with POST requests. If we had an endpoint that took in a POST request with an encoded JSON body, then sending the request in the test for that endpoint would look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Buffer&lt;/span&gt;
&lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewEncoder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;objectToSerializeToJSON&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;wr&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;httptest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewRecorder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;httptest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MethodPost&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"/post-endpoint"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;handlePostEndpointRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;wr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First we set up a &lt;code&gt;bytes.Buffer&lt;/code&gt; to use as our POST request's body. This is because a net/http Request's body needs to be an implementation of the &lt;a href="https://pkg.go.dev/io#Reader"&gt;io.Reader interface&lt;/a&gt;. &lt;code&gt;bytes.Buffer&lt;/code&gt; conveniently has the &lt;code&gt;Read&lt;/code&gt; method, so it implements that interface. We then use &lt;a href="https://pkg.go.dev/encoding/json#Encoder.Encode"&gt;json.NewEncoder(b).Encode&lt;/a&gt; to convert a Go struct into bytes of JSON that get stored in the buffer.&lt;/p&gt;

&lt;p&gt;We make our POST request by passing &lt;code&gt;MethodPost&lt;/code&gt;, rather than &lt;code&gt;MethodGet&lt;/code&gt;, into &lt;code&gt;httptest.NewRequest&lt;/code&gt;. Our &lt;code&gt;bytes.Buffer&lt;/code&gt; is passed in as the last argument to &lt;code&gt;NewRequest&lt;/code&gt; as the request body. Finally, just like before, we call our HTTP request handler using our ResponseRecorder and Request.&lt;/p&gt;

&lt;h2&gt;
  
  
  💻 The httptest server
&lt;/h2&gt;

&lt;p&gt;Not only does &lt;code&gt;httptest&lt;/code&gt; provide us a way to test our handlers with requests and responses, it even provides ways to test your code with a real HTTP server!&lt;/p&gt;

&lt;p&gt;A couple scenarios where this is useful are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When you're doing functional tests or integration tests for a web app. For example, testing that communication goes as expected between different microservices.&lt;/li&gt;
&lt;li&gt;If you are implementing clients to other web servers, you can define an httptest server giving back a response in order to test that your client can handle both sending the correct request and processing the server's response correctly.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's try out the latter of these scenarios, by making a client struct to send an HTTP request to our &lt;code&gt;/sloth&lt;/code&gt; endpoint, and deserialize the response into a struct.&lt;/p&gt;

&lt;p&gt;First, import &lt;code&gt;fmt&lt;/code&gt; and &lt;code&gt;encoding/json&lt;/code&gt; (and &lt;code&gt;net/http&lt;/code&gt; if you're putting the client code in its own file) and then write this code for the client. If you're newer to JSON deserialization, no worries if the code doesn't click 100% for you. The main things you need to know are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The client we're making has a &lt;code&gt;GetSlothfulMessage&lt;/code&gt; that sends an HTTP request to the &lt;code&gt;/sloth&lt;/code&gt; of its &lt;code&gt;baseURL&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Using Go's awesome &lt;code&gt;encoding/json&lt;/code&gt; package, the HTTP response body is converted to a &lt;code&gt;SlothfulMessage&lt;/code&gt; struct, which is returned if the request and JSON deserialization are successful. We are using &lt;a href="https://pkg.go.dev/encoding/json#Decoder.Decode"&gt;json.NewDecoder(res.Body).Decode&lt;/a&gt; for reading the response body into our &lt;code&gt;SlothfulMessage&lt;/code&gt; struct. &lt;/li&gt;
&lt;li&gt;If we get a non-200 HTTP status code sending the request, or there's a problem deserializing the JSON response, then &lt;code&gt;GetSlothfulMessage&lt;/code&gt; instead returns an error.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Client&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;httpClient&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Client&lt;/span&gt;
    &lt;span class="n"&gt;baseURL&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;SlothfulMessage&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Message&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`json:"message"`&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;NewClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;httpClient&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;baseURL&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Client&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;httpClient&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;httpClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;baseURL&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;    &lt;span class="n"&gt;baseURL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;GetSlothfulMessage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;SlothfulMessage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;httpClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;baseURL&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"/sloths"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusCode&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusOK&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="s"&gt;"got status code %d"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusCode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="n"&gt;SlothfulMessage&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewDecoder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We've got our client, so let's see how we can test it with an &lt;code&gt;httptest.Server&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;TestGetSlothfulMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;router&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewServeMux&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;router&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandleFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/sloth"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;handleSlothfulMessage&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;svr&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;httptest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;router&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;svr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;NewClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DefaultClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;svr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetSlothfulMessage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatalf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"error in GetSlothfulMessage: %v"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Message&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="s"&gt;"Stay slothful!"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="s"&gt;`message %s should contain string "Sloth"`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's what happens:&lt;/p&gt;

&lt;p&gt;First, we start our server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;    &lt;span class="n"&gt;svr&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;httptest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;appRouter&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;svr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We pass in our web app's HTTP router as a request handler for the server. When we run &lt;code&gt;NewServer&lt;/code&gt;, a server is set up to run on your localhost, on a randomized port. In fact, if you had your test run &lt;code&gt;time.Sleep&lt;/code&gt; to pause for a while, you could actually go to that server in your own browser!&lt;/p&gt;

&lt;p&gt;Now that we've got our server, we set up our client and have it test an HTTP roundtrip to our &lt;code&gt;/sloth&lt;/code&gt; endpoint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;    &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;NewClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DefaultClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;svr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetSlothfulMessage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The base URL we give to the &lt;code&gt;Client&lt;/code&gt;, is the URL of the server, which is the randomized port I mentioned earlier. So a request might go out to somewhere like "localhost:1123/sloths", or "localhost:5813/sloths". It all depends on which port &lt;code&gt;httptest.NewServer&lt;/code&gt; picks!&lt;/p&gt;

&lt;p&gt;Finally, we check that we didn't get an error, and that the response is what we expected. If we run go test -v, we'll get:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;=== RUN   TestHandleSlothfulMessage
-------- PASS: TestHandleSlothfulMessage (0.00s)
=== RUN   TestGetSlothfulMessage
    webapp_test.go:37: error in GetSlothfulMessage: got status code 404
-------- FAIL: TestGetSlothfulMessage (0.00s)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A failing test, because we got a 404 response, not the 200 we expected. So that means there's a bug in our client.&lt;/p&gt;

&lt;p&gt;The part of &lt;code&gt;GetSlothfulMessage&lt;/code&gt; that was for sending our HTTP request was:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;GetSlothfulMessage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;SlothfulMessage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;httpClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;baseURL&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"/sloths"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, we're sending the request to &lt;code&gt;c.baseURL + "/sloths"&lt;/code&gt;. We wanted to send it to &lt;code&gt;/sloth&lt;/code&gt;, not &lt;code&gt;/sloths&lt;/code&gt;. So fix that code, run &lt;code&gt;go test -v&lt;/code&gt;, and now...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;=== RUN   TestHandleSlothfulMessage
-------- PASS: TestHandleSlothfulMessage (0.00s)
=== RUN   TestGetSlothfulMessage
-------- PASS: TestGetSlothfulMessage (0.00s)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your test should pass!&lt;/p&gt;

&lt;p&gt;As you can see, with the &lt;code&gt;httptest&lt;/code&gt; package's &lt;code&gt;ResponseRecorder&lt;/code&gt; and &lt;code&gt;Server&lt;/code&gt; objects, we've got the ability to take the concepts we were already working with for writing tests using the &lt;code&gt;testing&lt;/code&gt; package, and then start using functionality to test both receiving and sending HTTP requests. Definitely a must-know package in a Go web developer's toolbelt!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Thank you to my coworker Aaron Taylor for peer-reviewing this blog post!&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>go</category>
      <category>testing</category>
      <category>codenewbie</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Subtesting, skipping, and cleanup in the Go testing.T</title>
      <dc:creator>Andy Haskell</dc:creator>
      <pubDate>Mon, 07 Jun 2021 16:00:05 +0000</pubDate>
      <link>https://dev.to/salesforceeng/subtesting-skipping-and-cleanup-in-the-go-testing-t-49ea</link>
      <guid>https://dev.to/salesforceeng/subtesting-skipping-and-cleanup-in-the-go-testing-t-49ea</guid>
      <description>&lt;p&gt;In &lt;a href="https://dev.to/salesforceeng/intro-to-automated-testing-in-go-4mjl"&gt;my last tutorial&lt;/a&gt;, we looked at the basics of writing tests in Go. We saw:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🚦 how the &lt;code&gt;testing.T&lt;/code&gt; type is used in all Go tests for managing the status of whether or not a Go test passed&lt;/li&gt;
&lt;li&gt;🐛 how we can use tests to catch a bug and fix our code to make a test pass&lt;/li&gt;
&lt;li&gt;🗄 how we can use table-testing in order to run tests cases with the same logic together&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are a good foundation to writing test coverage in Go, since any Go repository doing automated tests uses the standard library's testing package, and use the &lt;code&gt;testing.T&lt;/code&gt; type. But that's not all the tricks &lt;code&gt;testing.T&lt;/code&gt; has up its sleeve!&lt;/p&gt;

&lt;p&gt;In this tutorial, we'll look at how we can use three more methods in the &lt;code&gt;testing.T&lt;/code&gt; type in order to better organize your tests.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;💨 &lt;code&gt;t.Run&lt;/code&gt; to give your test cases subtests&lt;/li&gt;
&lt;li&gt;⏭ &lt;code&gt;t.Skip&lt;/code&gt;, for when we only want to run a test sometimes&lt;/li&gt;
&lt;li&gt;🧹 &lt;code&gt;t.Cleanup&lt;/code&gt;, for cleaning up state in between tests&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And when your tests are well-organized, that improves the quality of life for your dev team when it comes to knowing where to write your tests, and knowing how to fix a failing test. So let's dive in!&lt;/p&gt;

&lt;h2&gt;
  
  
  💨 Writing subtests for our Go tests
&lt;/h2&gt;

&lt;p&gt;As a quick recap, in the last tutorial, we wrote test coverage for a function telling us whether a string &lt;code&gt;IsSlothful&lt;/code&gt;, which returns true if either it contains the word sloth, or it contains the hibiscus emoji but &lt;strong&gt;not&lt;/strong&gt; the race car emoji.&lt;/p&gt;

&lt;p&gt;To make it easier to table-test that function, we made this assertion helper function, which has our &lt;code&gt;testing.T&lt;/code&gt; run its &lt;code&gt;Errorf&lt;/code&gt; method, causing the test to fail, if &lt;code&gt;IsSlothful&lt;/code&gt; doesn't return the expected value for the string we're testing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;assertIsSlothful&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;expected&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;IsSlothful&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;expected&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;expected&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"%s is supposed to be slothful"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"%s is not supposed to be slothful"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And we ran &lt;code&gt;assertIsSlothful&lt;/code&gt; in a loop on a slice of different test cases, like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;isSlothfulTestCase&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;str&lt;/span&gt;      &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="n"&gt;expected&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;isSlothfulTestCases&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;isSlothfulTestCase&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"hello, world!"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;                               &lt;span class="n"&gt;expected&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"hello, slothful world!"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;                      &lt;span class="n"&gt;expected&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Sloths rule!"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;                                &lt;span class="n"&gt;expected&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Nothing like an iced hibiscus tea! 🌺"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;       &lt;span class="n"&gt;expected&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Get your 🌺 flowers! They're going fast! 🏎️"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;expected&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;TestIsSlothful&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;isSlothfulTestCases&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;assertIsSlothful&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If one of the tests errors, then we get an error message about why the string isn't slothful. Say that we forgot to make checking for the word "sloth" case-insensitive. The error we get would look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;-------- FAIL: TestIsSlothful (0.00s)
    sloths_test.go:12: Sloths rule! is supposed to be slothful
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We have the descriptive error message of which string we expect to be slothful. But what if our &lt;code&gt;IsSlothful&lt;/code&gt; function got a lot more complex, to capture the many nuances of laziness? It would be nice to have a better description of exactly &lt;strong&gt;what&lt;/strong&gt; part of our functionality is being tested. And if we have hundreds of strings we want to test, it would be nice to zoom in on just one, or a few, test cases.&lt;/p&gt;

&lt;p&gt;That's where you can &lt;strong&gt;subtesting&lt;/strong&gt; can help you. Since Go 1.7, if inside your Go test, you run the &lt;code&gt;t.Run(string, func(*testing.T))&lt;/code&gt; method, your &lt;code&gt;testing.T&lt;/code&gt; will make a subtest within your test.&lt;/p&gt;

&lt;p&gt;To try it out, first let's take our &lt;code&gt;isSlothfulTestCase&lt;/code&gt; and give it a new string field called &lt;code&gt;testName&lt;/code&gt;, which is intended to be a brief description of what we're testing in each scenario. Then, let's add the &lt;code&gt;testName&lt;/code&gt; to each of our test cases:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;isSlothfulTestCases&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;isSlothfulTestCase&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt;
    &lt;span class="n"&gt;testName&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"string with nothing slothful isn't slothful"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;      &lt;span class="s"&gt;"hello, world!"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;expected&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;testName&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;`string with the substring "sloth" is slothful`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;      &lt;span class="s"&gt;"hello, slothful world!"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;expected&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;testName&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;`checking for the word "sloth" is case-insensitive`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;      &lt;span class="s"&gt;"Sloths rule!"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;expected&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;testName&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"strings with the 🌺 emoji are normally slothful"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;      &lt;span class="s"&gt;"Nothing like an iced hibiscus tea! 🧊🌺"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;expected&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;testName&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"the 🏎️ emoji negates the 🌺 emoji's slothfulness"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;      &lt;span class="s"&gt;"Get your 🌺 flowers! They're going fast! 🏎️"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;expected&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, let's update our main &lt;code&gt;TestIsSlothful&lt;/code&gt; testing loop to use subtesting:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;  func TestIsSlothful(t *testing.T) {
      for _, c := range isSlothfulTestCases {
&lt;span class="gd"&gt;-         assertIsSlothful(t, c.str, c.expected)
&lt;/span&gt;&lt;span class="gi"&gt;+         t.Run(c.testName, func(t *testing.T) {
+             assertIsSlothful(t, c.str, c.expected)
+         })
&lt;/span&gt;      }
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;t.Run&lt;/code&gt; takes in two arguments:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The name of our subtest, which will be the description we just added in the &lt;code&gt;testName&lt;/code&gt; field&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;func(t *testing.T)&lt;/code&gt; containing the code we want to run in the subtest. In this case, we are having the subtest just wrap the call to &lt;code&gt;assertIsSlothful&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now if we run &lt;code&gt;go test -v&lt;/code&gt;, the output looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ go test -v
=== RUN   TestIsSlothful
=== RUN   TestIsSlothful/string_with_nothing_slothful_isn't_slothful
=== RUN   TestIsSlothful/string_with_the_substring_"sloth"_is_slothful
=== RUN   TestIsSlothful/checking_for_the_word_"sloth"_is_case-insensitive
    sloths_test.go:12: Sloths rule! is supposed to be slothful
=== RUN   TestIsSlothful/strings_with_the_🌺_emoji_are_normally_slothful
=== RUN   TestIsSlothful/the_🏎️_emoji_negates_the_🌺_emoji's_slothfulness
-------- FAIL: TestIsSlothful (0.00s)
    --- PASS: TestIsSlothful/string_with_nothing_slothful_isn't_slothful (0.00s)
    --- PASS: TestIsSlothful/string_with_the_substring_"sloth"_is_slothful (0.00s)
    --- FAIL: TestIsSlothful/checking_for_the_word_"sloth"_is_case-insensitive (0.00s)
    --- PASS: TestIsSlothful/strings_with_the_🌺_emoji_are_normally_slothful (0.00s)
    --- PASS: TestIsSlothful/the_🏎️_emoji_negates_the_🌺_emoji's_slothfulness (0.00s)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We log output for each individual subtest now, rather than only seeing output for scenarios where the test failed. And now we see we got a failing subtest named &lt;code&gt;TestIsSlothful/checking_for_the_word_"sloth"_is_case-insensitive&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The slash in the name is used to indicate that a test being run is a subtest. And in addition to giving a name to the part of our top-level test that failed, you can even use a subtest as input to the &lt;code&gt;-run&lt;/code&gt; flag in the &lt;code&gt;go test&lt;/code&gt; command. If we have a whole lot of subtests and you want to zoom in on just one test case, like testing that checking for the word "sloth" is case-insensitive, you can run a command like &lt;code&gt;go test -v -run TestIsSlothful/case-insensitve&lt;/code&gt;, and the output will look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ go test -v -run "TestIsSlothful/case-insensitive"
=== RUN   TestIsSlothful
=== RUN   TestIsSlothful/checking_for_the_word_"sloth"_is_case-insensitive
    sloths_test.go:12: Sloths rule! is supposed to be slothful
-------- FAIL: TestIsSlothful (0.00s)
    --- FAIL: TestIsSlothful/checking_for_the_word_"sloth"_is_case-insensitive (0.00s)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, we run &lt;code&gt;TestIsSlothful&lt;/code&gt; like before, but we skip all of its subtests that don't match the name "case-insensitive"!&lt;/p&gt;

&lt;h2&gt;
  
  
  ⏭ Skipping tests with t.Skip
&lt;/h2&gt;

&lt;p&gt;One of the main benefits to writing automated tests is that you can do things like integrate them into continuous integration (CI) platforms, and you can then have rules on your team like that you only can merge changes if all of the test cases pass. Rules like that can help limit bringing in code that inadvertently breaks functionality because of unforeseen interactions between parts of the code.&lt;/p&gt;

&lt;p&gt;But you might have some complex tests that take a really long time to run, or that rely on external services where the test would fail if say, a service your code talks to is unavailable. Especially in the latter scenario, you don't want a different service's outage to bring your team's development work to a halt.&lt;/p&gt;

&lt;p&gt;You still want to run those more complex tests, but maybe only once in a while, rather than requiring the test to pass if you want to to bring in a code change. Luckily, there is a convenient workaround for this scenario: the &lt;code&gt;t.Skip&lt;/code&gt; method!&lt;/p&gt;

&lt;p&gt;To try it out, let's say we have a test for code to automate a quadcopter for feeding the lizards at a terrarium.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;TestQuadcopterDelivery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;q&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;ConnectToQuadcopter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"quadcopter-communication-info"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DeliverFood&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="s"&gt;"from-my-desk"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"to-terrarium"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"error delivering food: %v"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We could run this every time we do a CI test for a pull request, but that could fail if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The quadcopter is out of batteries&lt;/li&gt;
&lt;li&gt;The quadcopter isn't turned on&lt;/li&gt;
&lt;li&gt;Your friend is borrowing the quadcopter&lt;/li&gt;
&lt;li&gt;Someone bumped into the quadcopter&lt;/li&gt;
&lt;li&gt;The lizards aren't hungry&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So the test can't reliably pass every time we push some code.&lt;/p&gt;

&lt;p&gt;But let's say we tried running it at a set time where we know the quadcopter is there and charged, no one's gonna get in the way, and the lizards want a snack. Running a build at a certain time is called a &lt;strong&gt;nightly build&lt;/strong&gt;, and you might specify you're in a nightly build with something like whether a given environment variable is present, like &lt;code&gt;NIGHTLY_BUILD&lt;/code&gt;, or more accurately in this case, &lt;code&gt;SNACKTIME_BUILD&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To only run &lt;code&gt;TestQuadcopterDelivery&lt;/code&gt; only in a nightly build, we could modify the code like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;  func TestQuadcopterDelivery(t *testing.T) {
&lt;span class="gi"&gt;+     if _, ok := os.LookupEnv("SNACKTIME_BUILD"); !ok {
+         t.Skip("only running this test on snack build")
+     }
+ 
&lt;/span&gt;      q := ConnectToQuadcopter("quadcopter-communication-info")
      if err := q.DeliverFood(
          "from-my-desk", "to-terrarium",
      ); err != nil {
          t.Errorf("error delivering food: %v", err)
      }
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We check whether the &lt;code&gt;SNACKTIME_BUILD&lt;/code&gt; environment variable is present with &lt;code&gt;os.LookupEnv&lt;/code&gt;. If it returns false, we run &lt;code&gt;t.Skip&lt;/code&gt; and leave the message that we're only running that test case in a snack-time build. Otherwise, we run the test.&lt;/p&gt;

&lt;p&gt;So in our CI configuration for regular builds, we don't set that environment variable. But in our CI configuration for snack-time builds, we would set the variable. Now your dev team can efficiently build next-generation lizard-feeding! 🦎&lt;/p&gt;

&lt;h2&gt;
  
  
  🧹 Cleaning up after your test
&lt;/h2&gt;

&lt;p&gt;Finally, when you're writing more complicated tests, sometimes there are changes a test has to run that aren't totally contained in the test. Like changes to files, or putting data into databases. This can cause trouble when you're re-running a test, or running a test that uses a system that a different test had changed.&lt;/p&gt;

&lt;p&gt;There are different ways of addressing that, like per-test-case namespacing for your data, or mock systems like &lt;a href="https://github.com/spf13/afero"&gt;Afero memory filesystems&lt;/a&gt;, and cleaning up after each test case.&lt;/p&gt;

&lt;p&gt;For the latter of those, you can use things like &lt;a href="https://pkg.go.dev/github.com/stretchr/testify/suite"&gt;Testify Suite&lt;/a&gt; to handle cleanups, but since Go 1.14, the standard-library &lt;code&gt;testing.T&lt;/code&gt; type now has this new method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Cleanup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now when we write a test, we can specify a function that should run at the end of a test. Say we have a function that appends the gopher 🐹 (actually a hamster) emoji to a file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;addGopher&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filepath&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OpenFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filepath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;O_APPEND&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;O_WRONLY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0644&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"🐹"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We might test that like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;TestAddGopher&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// set up file to add a gopher to&lt;/span&gt;
    &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;filepath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"test-files"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"gopher-added.txt"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Go is awesome!"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c"&gt;// run addGopher and test that we now have a gopher emoji&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;addGopher&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;fileContents&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReadFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fileContents&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="s"&gt;"Go is awesome!🐹"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="s"&gt;`unexpected file contents %s`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fileContents&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We create a file at &lt;code&gt;./test-files/gopher-added.txt&lt;/code&gt;, write "Go is awesome!", use &lt;code&gt;addGopher&lt;/code&gt; to add the gopher emoji, and then check that the file now has the emoji.&lt;/p&gt;

&lt;p&gt;The test is correct, but what if a different test we ran later &lt;strong&gt;expected that there were no files in the &lt;code&gt;test-files&lt;/code&gt; directory&lt;/strong&gt;? That test would now fail without any of our code actually being broken, and when that happens, it can be a real pain.&lt;/p&gt;

&lt;p&gt;That's where cleanup after a test comes in. Let's give it a try:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;  func TestAddGopher(t *testing.T) {
      path := filepath.Join("test-files", "gopher-added.txt")
      f, err := os.CreateFile(path)
      if err != nil {
          t.Fatal(err)
      }

+     t.Cleanup(func() {
&lt;span class="gi"&gt;+         if err != os.Remove(path) {
+             t.Fatalf("error cleaning up %s: %v", path, err)
+         }
+     })
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, at the end of &lt;code&gt;TestAddGopher&lt;/code&gt;, we run our function to delete &lt;code&gt;test-files/gopher-added.txt&lt;/code&gt;. Now our other tests can run without having to worry about any data left over from &lt;code&gt;TestAddGopher&lt;/code&gt;!&lt;/p&gt;

&lt;p&gt;While that was just a contrived example, cleanup is important in a lot of complex tests working with interdependent systems. If you're coming from using testing systems like Jest in JavaScript, you can use &lt;code&gt;t.Cleanup&lt;/code&gt; in scenarios similar to where you would use the Jest &lt;code&gt;afterAll&lt;/code&gt; function; the Cleanup function runs &lt;strong&gt;after a test and all its subtests complete&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;As you can see, in addition to keeping track of the state of tests, the &lt;code&gt;testing.T&lt;/code&gt; type gives some great functionality for keeping your automated Go tests well-organized, and you can use that alongside techniques like table testing and CI build system setups.&lt;/p&gt;

&lt;p&gt;In my next tutorial on Go testing, we'll look at a different package in the standard library that will come in handy if you're a web developer like me: &lt;code&gt;net/http/httptest&lt;/code&gt;!&lt;/p&gt;

</description>
      <category>go</category>
      <category>testing</category>
      <category>codenewbie</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>I Used To Be Human: A Review of Digital Minimalism</title>
      <dc:creator>Logan Smith</dc:creator>
      <pubDate>Wed, 26 May 2021 16:13:14 +0000</pubDate>
      <link>https://dev.to/salesforceeng/i-used-to-be-human-a-review-of-digital-minimalism-56m8</link>
      <guid>https://dev.to/salesforceeng/i-used-to-be-human-a-review-of-digital-minimalism-56m8</guid>
      <description>&lt;p&gt;There was a time, not too long ago, when social media promised freedom from boredom, more robust community, greater efficiencies, and access to networks. However, these promises have come at the cost of our humanity. The addictive overuse of social media has led, as author and computer science professor Cal Newport argues, to increased anxiety, less focused productive work, and a decrease in meaningful relationships. These pressures have been amplified, no doubt, by the Covid-19 driven increase in remote work and the associated screen fatigue. &lt;/p&gt;

&lt;p&gt;In his book Digital Minimalism: Choosing a Focused Life in a Noisy World, Newport articulates his case for a life focused on deep value-add activities and reducing time spent in the “attention economy” or, as the title suggests, becoming a digital minimalist. This practice is sorely needed and especially timely in a post-pandemic world as we slowly emerge from our homes and reconnect with the people we’ve only seen via screens for the last year. &lt;/p&gt;

&lt;p&gt;Newport is an associate processor of computer science at Georgetown University and has authored several books, including Deep Work and A World Without Email. He is something of a tech-savvy and pop-culture Wendell Berry-lite for the 21st century as he encourages a distracted and anxious generation to stabilize around values of greater importance than the next trending hashtag. In Digital Minimalism, he successfully describes and defends this philosophy that prioritizes long-term meaning over short-term satisfaction and does so in two sections of his book. Part one focuses on the why-- or the foundation on which a digital minimalist philosophy is built. Part two answers the how and offers a pragmatic approach to living a digitally decluttered lifestyle. &lt;/p&gt;

&lt;p&gt;Part one begins by presenting the case for digital minimalism with a review of the concerning aspects of social media. As many techno-apologists quickly point out, there are seemingly endless advantages to leveraging these platforms; we use these tools to stay connected with old friends or join new communities of interest. But, Newport argues, it’s not the usefulness that is at contention. It’s the loss of autonomy. He points to Michael Zeiler’s research on pecking pigeons to illustrate that unpredictability is far more enticing than a constant outcome. In humans, unpredictability triggers the release of more dopamine and, therefore, has a greater addictive nature than the predictable outcomes. The top engineers in the world are working in Silicon Valley to win our attention and they use unpredictability (the number of likes or other metrics) to entice our constant scrolling. This attention economy--think Facebook, Twitter, Netflix, news headlines etc.--has turned us, the consumers, into products, as social media giants sell your attention to the highest bidder. &lt;/p&gt;

&lt;p&gt;To defend against this addiction, Newport proposes that consumers intentionally analyze each application and technology prior to downloading or engaging with it. He defines digital minimalism as: “A philosophy of technology used in which you focus online time on a small number of carefully selected and optimized activities that strongly support things you value and then happily miss out on everything else.”&lt;em&gt;1&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Instead of recommending a blanket ban on all social media, streaming services, video games, and other attention-consuming tech, Newport wisely suggests goals that are more attainable for the average digital consumer and shows his understanding of human psychology. For example, instead of deleting one’s Netflix account, Newport recommends only watching Netflix with friends or family. The principle and goal is to focus daily activities on items of true meaning and value.&lt;/p&gt;

&lt;p&gt;Part two focuses on how to engage with and enjoy a newly decluttered lifestyle. Newport suggests prioritizing solitude, rich and complex face-to-face conversations, and genuine leisure time. He not only highlights the benefits of these activities using ancient philosophy and modern neuroscience research but he provides practical suggestions on how to implement these recommendations. &lt;/p&gt;

&lt;p&gt;While Newport writes primarily about the digital consumer’s private decisions, I’d suggest that digital minimalism can--and should--find its way into the workplace, where emails, pings and unproductive Zoom meetings slowly eat away at productive hours and where we hone our fast-twitch muscles perusing a hundred unpredictable Slack channels, all in a futile attempt to be in the know. With the current corporate focus on health and well-being, employees should be empowered and encouraged to set digital boundaries and to focus, instead, on clear and precise deliverables.&lt;/p&gt;

&lt;p&gt;While Newport has composed an approachable and timely work on the necessity of slowing down and being intentional, he is missing one key element. He lays out many of the negative consequences of a distracted and anxious lifestyle but fails to answer, as the catechisms of old teach, what is the chief end (or purpose) of humankind. We know what we’re against; but what are we for? Without answering this question, digital minimalism may simply be the next fad, up there with Peloton and Hello Fresh. Perhaps embracing digital minimalism will create the mental space each of us needs to answer this for ourselves.&lt;/p&gt;

&lt;p&gt;To escape the mindless slot machine-like feedback loop of a mobile feed refresh, we may not need to “walk into the woods, to live deliberately.”&lt;em&gt;2&lt;/em&gt; But, Newport suggests, we must intentionally prioritize genuinely human activities like conversations and deep work in order to find the meaning this generation is craving. Perhaps Wendell Berry said it best. “Slow down. Pay attention. Do good work. Love your neighbors. Love your place. Stay in your place. Settle for less and enjoy it more.”&lt;em&gt;3&lt;/em&gt;&lt;/p&gt;

&lt;h6&gt;
  
  
  Footnotes:
&lt;/h6&gt;

&lt;h6&gt;
  
  
  1. Cal Newport, Digital Minimalism:Choosing a Focused Life in a Noisy World(New York: Portfolio/Penguin, 2019),28.
&lt;/h6&gt;

&lt;h6&gt;
  
  
  2. Henry David Thoreau, Walden; or, Life in the Woods(New York: Dover Publications,2012),59.
&lt;/h6&gt;

&lt;h6&gt;
  
  
  3. Wendell Berry, The World Ending Fire: The Essential Wendell Berry(California: Counterpoint, 2017),x.
&lt;/h6&gt;

</description>
      <category>employeesuccess</category>
      <category>successfromanywhere</category>
      <category>digitalminimalism</category>
    </item>
    <item>
      <title>Engineer more than software</title>
      <dc:creator>Laura Lindeman</dc:creator>
      <pubDate>Wed, 24 Mar 2021 16:16:27 +0000</pubDate>
      <link>https://dev.to/salesforceeng/engineer-more-than-software-14n7</link>
      <guid>https://dev.to/salesforceeng/engineer-more-than-software-14n7</guid>
      <description>&lt;p&gt;Salesforce engineers are builders. Together, we’ve created a platform that helps companies around the world connect with their customers. Driven by our commitment to trust, equality, and innovation, we’re contributing to a more collaborative and inclusive world. Learn more at &lt;a href="http://salesforce.com/tech"&gt;salesforce.com/tech&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/ioinFHta938"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

</description>
      <category>career</category>
      <category>hiring</category>
      <category>inclusion</category>
    </item>
    <item>
      <title>Intro to automated testing in Go</title>
      <dc:creator>Andy Haskell</dc:creator>
      <pubDate>Tue, 09 Mar 2021 18:47:02 +0000</pubDate>
      <link>https://dev.to/salesforceeng/intro-to-automated-testing-in-go-4mjl</link>
      <guid>https://dev.to/salesforceeng/intro-to-automated-testing-in-go-4mjl</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This blog post is adapted from an intro to testing talk I recently did at &lt;a href="https://meetup.com/orlango"&gt;OrlanGo&lt;/a&gt;'s virtual meetup. You can find the slides in &lt;a href="https://github.com/andyhaskell/orlango-testing-talk"&gt;this GitHub repository&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There are a lot of features to the Go programming language that I really like, and one of my favorites is that writing automated tests in Go is really encouraged.&lt;/p&gt;

&lt;p&gt;The moment you install Go, right out of the box without having to install &lt;strong&gt;anything else&lt;/strong&gt;, you have access to a Go test runner for automated testing. I've personally written Go contributing to open source, working at a startup, and today working at Salesforce, and the convenience of testing in Go has always helped me build. So in this tutorial, I would like to show you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;💡 Why write automated Go tests?&lt;/li&gt;
&lt;li&gt;🐹 How you'll use the &lt;code&gt;testing&lt;/code&gt; package in Go&lt;/li&gt;
&lt;li&gt;📋 What testing your Go code will look like as part of your workflow&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you're coming to Go from automated testing in Jest or RSpec or you're new to automated testing as a whole, this tutorial is for you!&lt;/p&gt;

&lt;h2&gt;
  
  
  💭 Why write tests?
&lt;/h2&gt;

&lt;p&gt;When we're building an app, we're already maintaining a lot of code to begin with, so we should have a good reason if we're going to be writing some more. So here are some benefits to giving your code test coverage:&lt;/p&gt;

&lt;p&gt;First, writing tests has you &lt;strong&gt;write out each category of scenario your code is intended to work with&lt;/strong&gt;. This way, when you are writing the main code for your software, you have those scenarios in mind. In fact, some engineers even write out the test coverage for the code they're writing and then write the code. That technique is called &lt;strong&gt;test-driven development&lt;/strong&gt; and it's not everyone's thing, but it's worth a try!&lt;/p&gt;

&lt;p&gt;Another benefit is that since big software projects are made of smaller pieces of code, writing tests &lt;strong&gt;helps you make those smaller pieces of code serve as a source of truth&lt;/strong&gt;. That way when you're building with those units of code, you have confidence that they work as expected.&lt;/p&gt;

&lt;p&gt;Also, if you have automated testing, something machines are great at is &lt;strong&gt;repeating a test in exactly the same way&lt;/strong&gt;. That's not to say manual testing doesn't have a place in software development, since you do want to make sure your app makes sense and is accessible for a human to use, but when precise repeatability is what you need, automation is your friend.&lt;/p&gt;

&lt;p&gt;Finally, and I find Go is especially conducive to this, in a big codebase, &lt;strong&gt;tests serve as more documentation&lt;/strong&gt;; if the main documentation for a Go package doesn't click for me, my next stop is to look at its test coverage to see real-world usage to a function or interface.&lt;/p&gt;

&lt;p&gt;Sounds like some great reasons to write tests, so let's see how to write and run a test in Go!&lt;/p&gt;

&lt;h2&gt;
  
  
  🌺 A slothful "hello world" of Go testing
&lt;/h2&gt;

&lt;p&gt;Let's start by getting some code to test in Go. If you're following along, make a folder titled &lt;code&gt;sloths&lt;/code&gt; and put the following code into a file &lt;code&gt;sloths/sloths.go&lt;/code&gt;. This code will tell you whether or not a string &lt;code&gt;IsSlothful&lt;/code&gt;,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;sloths&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"strings"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;IsSlothful&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"sloth"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A string is considered slothful by this function if it contains the word "sloth".&lt;/p&gt;

&lt;p&gt;Since we're doing a "hello world" of tests, let's test whether "hello world!" is a slothful string. Since it doesn't contain the word "sloth", we expect that &lt;code&gt;IsSlothful&lt;/code&gt; will return false. Let's see what a Go test for that looks like. Put the following code in &lt;code&gt;sloths_test.go&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;sloths&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"testing"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;TestIsSlothful&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;IsSlothful&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"hello, world!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"hello, world! is not supposed to be slothful"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Before we take a look at what's going on in the test, let's try running it. As I mentioned in the beginning, the test runner is built into Go, and what that means is under the &lt;code&gt;go&lt;/code&gt; command, there is a &lt;code&gt;test&lt;/code&gt; subcommand that runs the tests.&lt;/p&gt;

&lt;p&gt;In the command line, change your working directory to your &lt;code&gt;sloths&lt;/code&gt; directory, and run &lt;code&gt;go test -v&lt;/code&gt;. Your command line output should look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;=== RUN   TestIsSlothful
-------- PASS: TestIsSlothful (0.00s)
PASS
ok      github.com/andyhaskell/orlango-testing-talk/sloths    0.227s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Congratulations! You just ran a Go test, and it passed!&lt;/p&gt;

&lt;h2&gt;
  
  
  👀 Taking a closer look at our tests
&lt;/h2&gt;

&lt;p&gt;Now let's see how that test worked. That was a small test function, but it has four things to bring your attention to.&lt;/p&gt;

&lt;p&gt;First, take another look at the import block for the Go code. In addition to Go coming with its &lt;code&gt;go test&lt;/code&gt; test runner out of the box, &lt;strong&gt;the Go standard library includes a &lt;code&gt;testing&lt;/code&gt; package&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"testing"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The main thing in there you will be working with is its &lt;code&gt;testing.T&lt;/code&gt; object, which we'll see provides a small set of rules for managing a Go test.&lt;/p&gt;

&lt;p&gt;Second, there's the &lt;strong&gt;function signature&lt;/strong&gt; to a Go test&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;TestIsSlothful&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All Go test functions have two things in common: they take in a &lt;code&gt;testing.T&lt;/code&gt; as their only argument, and &lt;code&gt;Test&lt;/code&gt; is the first camelCase word of their name. This tells the &lt;code&gt;go test&lt;/code&gt; command which functions it needs to run in a Go package.&lt;/p&gt;

&lt;p&gt;Third, let's take a look at how we write assertions in Go. In languages like JavaScript or Ruby, a test that we expect IsSlothful to return false for "hello, world!" would look something like these, reading like a sentence in English:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;IsSlothful&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hello, world!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nx"&gt;toBeFalse&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If &lt;code&gt;IsSlothful&lt;/code&gt; returns true, then the &lt;code&gt;expect&lt;/code&gt; fails, causing the test to fail.&lt;/p&gt;

&lt;p&gt;In Go on the other hand, &lt;strong&gt;a test fails if its testing.T is made to fail&lt;/strong&gt;. Our assertion was written in Go like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;IsSlothful&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"hello, world!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"hello, world! is not supposed to be slothful"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If &lt;code&gt;IsSlothful&lt;/code&gt; were to return true, then we call our T's &lt;code&gt;Error&lt;/code&gt; method, causing the &lt;code&gt;testing.T&lt;/code&gt; to fail with an error message explaining what went wrong. As you can see, this is a regular Go if statement; &lt;strong&gt;Go testing ultimately is Go code that happens to use the testing package&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In addition to &lt;code&gt;t.Error&lt;/code&gt;, there's three other ways to make a &lt;code&gt;testing.T&lt;/code&gt; fail:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;t.Fail&lt;/code&gt;, which is like &lt;code&gt;t.Error&lt;/code&gt;, but it causes the &lt;code&gt;testing.T&lt;/code&gt; to fail without an error message&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;t.Fatal&lt;/code&gt;, which is like &lt;code&gt;t.Error&lt;/code&gt;, but makes the test stop immediately

&lt;ul&gt;
&lt;li&gt;This makes &lt;code&gt;Fatal&lt;/code&gt; good for when you get an error where the results of code in the test past that point wouldn't make sense (for example if a preliminary step fails).&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;t.FailNow&lt;/code&gt;, which is like &lt;code&gt;t.Fail&lt;/code&gt;, but it stops the test immediately.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The fourth and final thing I would like to draw your attention to is the directory structure we have so far.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.
├── sloths.go
└── sloths_test.go
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;All test files in Go have a name that ends with the &lt;code&gt;_test.go&lt;/code&gt; suffix&lt;/strong&gt;, which tells the &lt;code&gt;go test&lt;/code&gt; command line tool where to find the test code for your Go project.&lt;/p&gt;

&lt;p&gt;The other thing this does is for the coder. Because &lt;code&gt;go test&lt;/code&gt; requires all your test files to be named this way, that means if you join an engineering team that does Go, or you start contributing to an open source project in Go, &lt;strong&gt;right on day 1&lt;/strong&gt; you can find where all the testing code is!&lt;/p&gt;

&lt;p&gt;Now that we took a closer look at Go tests, let's try giving our &lt;code&gt;IsSlothful&lt;/code&gt; function some more test coverage.&lt;/p&gt;

&lt;h2&gt;
  
  
  🐛 Catching a bug with a Go test
&lt;/h2&gt;

&lt;p&gt;We've got our &lt;code&gt;TestIsSlothful&lt;/code&gt; function, but it could use some more assertions. When you're writing test coverage, you want to test each general category of scenario your code works with. So for &lt;code&gt;IsSlothful&lt;/code&gt;, that's:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Passing in a string containing the word "sloth", which should return true&lt;/li&gt;
&lt;li&gt;Passing in a string not containing the word "sloth", which should return false as we already tested&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So let's give our &lt;code&gt;TestIsSlothful&lt;/code&gt; function some more assertions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;IsSlothful&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"hello, slothful world!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"hello, slothful world! is supposed to be slothful"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;IsSlothful&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Sloths rule!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Sloths rule! is supposed to be slothful"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We're testing the strings &lt;code&gt;hello, slothful world!&lt;/code&gt;, and &lt;code&gt;Sloths rule!&lt;/code&gt;, expecting our IsSlothful function to return true for both of them.&lt;/p&gt;

&lt;p&gt;Let's see if it does by running &lt;code&gt;go test -v&lt;/code&gt; again.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;=== RUN   TestIsSlothful
    sloths_test.go:17: Sloths rule! is supposed to be slothful
-------- FAIL: TestIsSlothful (0.00s)
exit status 1
FAIL    github.com/andyhaskell/orlango-testing-talk/sloths    0.207s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The test failed, but that means our test did its job; it found a bug in our &lt;code&gt;IsSlothful&lt;/code&gt; function; the string "Sloths rule!" is not considered a slothful string, even though it contains the word "sloth".&lt;/p&gt;

&lt;p&gt;Looking at our code, the reason why is because we were passing the string into &lt;code&gt;strings.Contains&lt;/code&gt; to look for the word "sloth" in all-lowercase. So an uppercase "Sloths rule!" goes undetected; we should have compared the string passed in with the word "sloth", case-insensitive. And luckily, the Go &lt;code&gt;strings&lt;/code&gt; package has a function for fixing that. Let's check that out.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;  func IsSlothful(s string) bool {
&lt;span class="gi"&gt;+     s = strings.ToLower(s)
+
&lt;/span&gt;      if strings.Contains(s, "sloth") {
          return true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Before going into the if statements, we make our string all-lowercase. Now try &lt;code&gt;go test -v&lt;/code&gt; again and your test should pass!&lt;/p&gt;

&lt;h2&gt;
  
  
  🏗 Trying out some Go test-driven development
&lt;/h2&gt;

&lt;p&gt;With our &lt;code&gt;IsSlothful&lt;/code&gt; function now having plenty of test coverage, we're in a good place to give it some more logic. And we need that because there's more slothful strings out there.&lt;/p&gt;

&lt;p&gt;Sloths love eating hibiscus flowers, so a string with the hibiscus emoji is slothful. But sloths are also laid-back and not in a rush, so if a string has the hibiscus emoji but also the race car emoji, that string isn't slothful.&lt;/p&gt;

&lt;p&gt;To try out a test-driven development workflow, let's start adding to our testing logic in &lt;code&gt;sloths_test.go&lt;/code&gt; rather than &lt;code&gt;sloths.go&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;TestHibiscusEmoji&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;IsSlothful&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Nothing like an iced hibiscus tea! 🌺"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Nothing like an iced hibiscus tea! 🌺 "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
            &lt;span class="s"&gt;"is supposed to be slothful"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;IsSlothful&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Get your 🌺 flowers! They're going fast! 🏎️"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Get your 🌺 flowers! They're going fast! 🏎️ "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
            &lt;span class="s"&gt;"is not supposed to be slothful"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We're testing that we expect the string "Nothing like an iced hibiscus tea! 🌺" to be slothful, but that we expect "Get your 🌺 flowers! They're going fast! 🏎️" not to be slothful.&lt;/p&gt;

&lt;p&gt;Run &lt;code&gt;go test -v&lt;/code&gt; again and the results should look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;=== RUN   TestIsSlothful
-------- PASS: TestIsSlothful (0.00s)
=== RUN   TestHibiscusEmoji
    sloths_test.go:22: Nothing like an iced hibiscus tea! 🌺 is supposed to be slothful
-------- FAIL: TestHibiscusEmoji (0.00s)
exit status 1
FAIL    github.com/andyhaskell/orlango-testing-talk/sloths    0.234s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our test failed again, but in TDD that's a good thing; in TDD we see our tests fail so that we know a test passed specifically &lt;strong&gt;because&lt;/strong&gt; of our code change.&lt;/p&gt;

&lt;p&gt;For the fix, we need to add an extra if statement to indicate that one more scenario where a string is slothful is when it contains the hibiscus emoji, but not the race car emoji.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;  func IsSlothful(s string) bool {
      s = strings.ToLower(s)
&lt;span class="gi"&gt;+     slothsLikeThis := strings.Contains(s, "🌺") &amp;amp;&amp;amp;
+         !strings.Contains(s, "🏎️")
&lt;/span&gt;
      if strings.Contains(s, "sloth") {
          return true
&lt;span class="gi"&gt;+     } else if slothsLikeThis {
+         return true
&lt;/span&gt;      }
      return false
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With our new piece of logic added, we're ready to try the test again.&lt;/p&gt;

&lt;p&gt;Run &lt;code&gt;go test -v&lt;/code&gt; one more time and...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;=== RUN   TestIsSlothful
-------- PASS: TestIsSlothful (0.00s)
=== RUN   TestHibiscusEmoji
-------- PASS: TestHibiscusEmoji (0.00s)
PASS
ok      github.com/andyhaskell/orlango-testing-talk/sloths    0.245s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All our tests passed; our refactor is complete!&lt;/p&gt;

&lt;p&gt;By the way, if you have a lot of tests and want to just run a few, you can use the &lt;code&gt;-run&lt;/code&gt; flag on go test, which only runs tests matching the regular expression passed into the &lt;code&gt;-run&lt;/code&gt; flag.&lt;/p&gt;

&lt;p&gt;For example, to run just TestHibiscus, you can run &lt;code&gt;go test -v -run Hibiscus&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  🗄 A table-testing refactor
&lt;/h2&gt;

&lt;p&gt;So far in our Go tests, we have two test functions running five assertions, but they all have the same structure; we pass in a string to &lt;code&gt;IsSlothful&lt;/code&gt; and check that the returned boolean is what we expected; if we get back the wrong result, then we run &lt;code&gt;t.Error&lt;/code&gt; causing the test to fail.&lt;/p&gt;

&lt;p&gt;Since all our assertions have the same structure, it would be nice if we made a helper function for our assertion so we can run our tests in one big loop. That technique is popular in Go, and it's called &lt;strong&gt;table testing&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;To start, let's write a helper function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;assertIsSlothful&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;expected&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;IsSlothful&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;expected&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;expected&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"%s is supposed to be slothful"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"%s is not supposed to be slothful"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The parameters to our function are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;testing.T&lt;/code&gt;; if we make a helper function that handles assertions, then that function needs access to our &lt;code&gt;testing.T&lt;/code&gt; object so we can make the test fail if our assertion fails.&lt;/li&gt;
&lt;li&gt;The string we want to test&lt;/li&gt;
&lt;li&gt;The expected result of &lt;code&gt;IsSlothful&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Inside the helper function, we compare the result of passing our string to &lt;code&gt;IsSlothful&lt;/code&gt; with the expected value. If the results don't match, we make the fail test with &lt;code&gt;t.Errorf&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Errorf&lt;/code&gt; and &lt;code&gt;Fatalf&lt;/code&gt; are variations on the &lt;code&gt;Error&lt;/code&gt; and &lt;code&gt;Fatal&lt;/code&gt; methods; rather than taking in just a string for our error message, we pass in a template with percent-sign parameters, and then additional arguments for "filling in the blanks", similar to &lt;code&gt;fmt.Printf&lt;/code&gt; and &lt;code&gt;fmt.Sprintf&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now, let's set up our test cases to loop over.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;isSlothfulTestCase&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;str&lt;/span&gt;      &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="n"&gt;expected&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;isSlothfulTestCases&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;isSlothfulTestCase&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"hello, world!"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;                               &lt;span class="n"&gt;expected&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"hello, slothful world!"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;                      &lt;span class="n"&gt;expected&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Sloths rule!"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;                                &lt;span class="n"&gt;expected&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Nothing like an iced hibiscus tea! 🌺"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;       &lt;span class="n"&gt;expected&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Get your 🌺 flowers! They're going fast! 🏎️"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;expected&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We have a slice of &lt;code&gt;isSlothful&lt;/code&gt; test cases; if one of them fails, then the string will appear in the error message.&lt;/p&gt;

&lt;p&gt;We have a pretty simple assertion we're testing, but if you were doing a more complicated assertion, or it isn't quite clear &lt;strong&gt;what&lt;/strong&gt; is being tested (like writing test coverage for an obscure edge case), then an additional field you might add to your test case struct might be a &lt;code&gt;description&lt;/code&gt; string that your error message can include to provide more detail on your test case if it failed.&lt;/p&gt;

&lt;p&gt;Now let's see what our new &lt;code&gt;IsSlothful&lt;/code&gt; function looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;TestIsSlothful&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;isSlothfulTestCases&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;assertIsSlothful&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We loop over our &lt;code&gt;isSlothfulTestCases&lt;/code&gt;, and we run &lt;code&gt;assertIsSlothful&lt;/code&gt; on each one, printing the strings that failed the test if any did.&lt;/p&gt;

&lt;p&gt;If you see code that that gets repeated a lot in your team's tests and essentially makes one logical step of the test, that might be a good opportunity to use a helper function to simplify your tests. Sometimes there might be too much detail in the code you refactor out for a helper function to be worth it. But used reasonably, custom assertions can help make your tests easier to read.&lt;/p&gt;

&lt;h2&gt;
  
  
  🔭 Where to check out next with tests
&lt;/h2&gt;

&lt;p&gt;We've looked at how we can write Go tests with the standard library and the &lt;code&gt;go test&lt;/code&gt; tool. But testing is a huge topic; when I presented this at OrlanGo, we had about half an hour of interesting roundtable discussion afterward on people's testing techniques. So you might be wondering where to go next.&lt;/p&gt;

&lt;p&gt;The good news is, since &lt;code&gt;testing.T&lt;/code&gt; handles the rules of Go tests, if you have a good grasp of the fundamentals of Go, you're already in a great place to start writing test coverage in Go; tests in Go are essentially Go code that happens to use a &lt;code&gt;testing.T&lt;/code&gt; struct.&lt;/p&gt;

&lt;p&gt;Additionally, because of Go's small set of syntax rules compared to many other languages, if you're going into a Go codebase and the documentation doesn't give you all the answers you're looking for on how to use some code, you can also read the tests for that piece of code. Those often illustrate how the code is intended to be used. Speaking of, contributing automated tests also is an excellent way to contribute to open source!&lt;/p&gt;

&lt;p&gt;Also, since Go is especially popular for backend web development, Go's standard library actually provides a testing package specifically for making it easier to test your HTTP handlers and clients. &lt;code&gt;net/http/httptest&lt;/code&gt; gives you code like an implementation of the &lt;code&gt;http.ResponseWriter&lt;/code&gt; for checking that you got back the HTTP response you expected. Additionally it even gives you code for setting up an HTTP server your tests can use, which helps a ton when you're testing clients for web APIs.&lt;/p&gt;

&lt;p&gt;Finally, outside the standard library, a lot of assertions, like whether two values are equal to each other, or whether a given value is nil, or whether a function errored, are so common that Mat Ryer, a famous Gopher, actually wrote a Go testing package called &lt;a href="https://github.com/stretchr/testify"&gt;Testify&lt;/a&gt;. Inside it, you'll find a lot of assertions that feel similar to Jest or RSpec matchers. It also has a &lt;code&gt;suite&lt;/code&gt; package, which helps you run setup and teardown code before each test case or group of test cases. My slides for the talk this blog post came from give a quick look at Testify, and you can find them in &lt;a href="https://github.com/andyhaskell/orlango-testing-talk"&gt;this GitHub repository&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>go</category>
      <category>testing</category>
      <category>codenewbie</category>
      <category>beginners</category>
    </item>
    <item>
      <title>2020 Year in Review</title>
      <dc:creator>Laura Lindeman</dc:creator>
      <pubDate>Wed, 06 Jan 2021 15:11:47 +0000</pubDate>
      <link>https://dev.to/salesforceeng/2020-year-in-review-490f</link>
      <guid>https://dev.to/salesforceeng/2020-year-in-review-490f</guid>
      <description>&lt;p&gt;2020 was (dare we say it?) an unprecedented year, but before it's fully in the rearview, we at Salesforce Engineering wanted to take a beat and look back at 10 good things that happened.&lt;/p&gt;

&lt;p&gt;10. With our thousands of employees forced to leave their offices and work remotely, we took the opportunity to develop new practices and guidelines for distributed work. We'll be better able to effectively communicate, create, and collaborate together no matter what the next year(s) hold.&lt;br&gt;&lt;br&gt;
9. We published a lot of &lt;a href="https://www.engineering.salesforce.com"&gt;blog posts&lt;/a&gt;! Our top three most-read posts covered security (&lt;a href="https://engineering.salesforce.com/easily-identify-malicious-servers-on-the-internet-with-jarm-e095edac525a"&gt;Easily Identify Malicious Servers on the Internet with JARM&lt;/a&gt;), automated testing (&lt;a href="https://engineering.salesforce.com/automating-complex-end-to-end-tests-b0a5fc003592"&gt;Automating Complex End-to-end Tests&lt;/a&gt;), and an open source tool for Kubernetes (&lt;a href="https://engineering.salesforce.com/a-generic-sidecar-injector-for-kubernetes-c05eede1f6bb"&gt;A Generic Sidecar Injector for Kubernetes&lt;/a&gt;).&lt;br&gt;&lt;br&gt;
8. We sponsored the first-ever virtual Grace Hopper Celebration put on by Anita Borg and extended internship offers to a slew of folks we’re looking forward to welcoming to the team next summer.&lt;br&gt;&lt;br&gt;
7. In a truly strange year, almost 300 employees took to the virtual stage at conferences around the world (er, in their living rooms?) to talk about the great work they’re doing.&lt;br&gt;&lt;br&gt;
6. It’s no secret we love open source. We headed to the StackOverflow blog to share &lt;a href="https://stackoverflow.blog/2020/11/17/the-complexities-and-rewards-of-open-sourcing-corporate-software-products/"&gt;the complexities and rewards of open sourcing corporate software projects&lt;/a&gt;.&lt;br&gt;&lt;br&gt;
5. Speaking of open source, we dropped some cool projects this year: &lt;a href="https://github.com/salesforce/best"&gt;Best&lt;/a&gt;, which allows you to write JavaScript benchmarks in the same way you write unit tests and integrate it into your continuous integration workflow; the &lt;a href="https://einstein.ai/the-ai-economist"&gt;AI Economist&lt;/a&gt;, which is an open source framework for economic policy design; and &lt;a href="https://github.com/salesforce/cloudsplaining"&gt;Cloudsplaining&lt;/a&gt;, an AWS IAM Security Assessment tool that identifies violations of least privilege and generates a risk-prioritized HTML report, among &lt;a href="https://github.com/salesforce"&gt;many others&lt;/a&gt;.&lt;br&gt;&lt;br&gt;
4. We launched the FOSS Fund to donate money every quarter to a project selected by our employees; a sustainable open source ecosystem is essential for our technical future.&lt;br&gt;&lt;br&gt;
3. The world got to meet the &lt;a href="https://vmblog.com/archive/2020/10/30/how-salesforce-operates-kubernetes-multitenant-clusters-in-public-cloud-at-scale.aspx#.X-uar-lKjlx"&gt;Salesforce Kubernetes Platform&lt;/a&gt;, a substrate-agnostic Kubernetes install that handles concerns for the entire runtime stack.&lt;br&gt;&lt;br&gt;
2. The Buildpacks project was &lt;a href="https://www.cncf.io/blog/2020/11/18/toc-approves-cloud-native-buildpacks-from-sandbox-to-incubation/"&gt;promoted to Incubation&lt;/a&gt; from the Cloud Native Computing Foundation Sandbox.&lt;br&gt;&lt;br&gt;
1. We &lt;a href="https://www.salesforce.com/news/press-releases/2020/12/02/introducing-salesforce-hyperforce/"&gt;announced Hyperforce&lt;/a&gt;, a complete re-architecture of Salesforce that uses the scale &amp;amp; agility of the public cloud, representing a massive, multi-year, cross-company engineering effort that we’re so proud of.  &lt;/p&gt;

&lt;p&gt;So that’s a wrap on 2020. It was a difficult year, making it all the more worth looking back on what we accomplished together! We're already back at it after taking a short breather around the holidays and hope to bring you more great stuff in 2021.&lt;/p&gt;

</description>
      <category>news</category>
      <category>devjournal</category>
      <category>motivation</category>
    </item>
    <item>
      <title>Salesforce Employees Make 178 Open Source Contributions During Hacktoberfest!</title>
      <dc:creator>Laura Lindeman</dc:creator>
      <pubDate>Thu, 19 Nov 2020 14:42:44 +0000</pubDate>
      <link>https://dev.to/salesforceeng/salesforce-employees-make-178-open-source-contributions-during-hacktoberfest-1774</link>
      <guid>https://dev.to/salesforceeng/salesforce-employees-make-178-open-source-contributions-during-hacktoberfest-1774</guid>
      <description>&lt;p&gt;&lt;em&gt;by Alyssa Arvin, Sr. Open Source Program Manager&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Salesforce engineers are builders.
&lt;/h3&gt;

&lt;p&gt;Together, we’ve created a platform that helps companies around the world connect with their customers and establish lasting, trusted relationships. Whether we’re working with a small business, a nonprofit, or a Fortune 500 company, it’s our job to ensure all systems are always a go. And with thousands of customers and tens of millions of daily users on our platform, our aim is to keep pushing boundaries on just how massively we can scale.&lt;/p&gt;

&lt;p&gt;We’re also building a team of problem solvers who believe technology creates meaningful progress when the people behind it progress together. Driven by our commitment to trust, equality, and innovation, we’re contributing to a more collaborative, inclusive, and connected world. We contribute to thousands of open source projects every year, from key technologies powering our innovation to community projects that make our world a better place.&lt;/p&gt;

&lt;p&gt;We couldn’t let October pass without participating in Hacktoberfest. This year looked a little different and it actually came with better results!&lt;/p&gt;

&lt;p&gt;This year we had 52 people participate in Hacktoberfest with a 178 total open source contributions!  Almost half of the participants made 4 or more contributions. Our employees also gave 71 hours to &lt;a href="https://engineering.salesforce.com/bringing-salesforces-pledge-1-to-open-source-1e2cf74fce97"&gt;volunteering through open source&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  How did we run Hacktoberfest at Salesforce?
&lt;/h3&gt;

&lt;p&gt;The biggest theme of our Hacktoberfest was.... THEMES! We came up with themes for each week to help inspire people to contribute. The themes were:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Week 1: Project you know &amp;amp; love&lt;/li&gt;
&lt;li&gt;Week 2: Projects that were &lt;a href="https://github.com/salesforce"&gt;released by Salesforce employees&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Week 3: Projects we depend on at Salesforce&lt;/li&gt;
&lt;li&gt;Week 4: Volunteering through open source&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Our employees didn’t &lt;em&gt;have&lt;/em&gt; to stick to the themes. If they wanted to make contributions throughout the entire month to one project they loved, then they could do that! However, the themes were really helpful in getting new open source contributors to see what projects were out there.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“It's a great introduction to the open source world and has a lot of community support that beginner contributors are looking for.” - Swati Kothari&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This year we skipped things like tech talks, office hours, and synchronous events and instead encouraged people to contribute when they wanted to. The great thing about this is that it allowed anyone to participate no matter what time zone they were working in. We had a huge turnout from our employees in India and Tel Aviv.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“This was really fantastic, exciting and energetic event. I was quite amazed to see many Salesforce employees all around the globe participating in various open source projects while working from home. And I am sure anyone who loves coding to the core would feel the same.” -Viraj Jasani&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We also followed DigitalOcean’s lead to make Hacktoberfest easier on open source projects. We encouraged our employees to use Hacktoberfest’s &lt;a href="https://github.com/topics/hacktoberfest"&gt;list of projects&lt;/a&gt; and to only make meaningful contributions. For projects that were released by Salesforce employees, we made sure the maintainers wanted their project listed as an opportunity. The projects listed under the volunteering theme were previous projects that we had used, so we knew the maintainers were comfortable accepting contributions. &lt;/p&gt;

&lt;h3&gt;
  
  
  Reflections
&lt;/h3&gt;

&lt;p&gt;It is always fun to try new ways to get people contributing to open source. What are some ways that you have encouraged employees? Let us know on Twitter &lt;a href="https://twitter.com/SalesforceEng"&gt;@SalesforceEng&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>hacktoberfest</category>
      <category>opensource</category>
      <category>codenewbie</category>
    </item>
    <item>
      <title>How an SRE became an Application Security Engineer (and you can too)</title>
      <dc:creator>Laura Lindeman</dc:creator>
      <pubDate>Wed, 28 Oct 2020 13:24:24 +0000</pubDate>
      <link>https://dev.to/salesforceeng/how-an-sre-became-an-application-security-engineer-and-you-can-too-1bdi</link>
      <guid>https://dev.to/salesforceeng/how-an-sre-became-an-application-security-engineer-and-you-can-too-1bdi</guid>
      <description>&lt;p&gt;&lt;em&gt;by &lt;a href="https://twitter.com/breanneboland"&gt;Breanne Boland&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I realized I found security really interesting early on in my career as an engineer, back in 2015. It was a useful complement to infrastructure and networking, the other interests I quickly picked up. However, while security roles are notoriously hard to fill, they’re also notoriously hard to get when you haven’t had one before. I assumed security work would be something I’d pursue once I felt more grounded in my skills as a site reliability engineer – meaning I might have waited forever, if left to my own self-education.&lt;/p&gt;

&lt;p&gt;Instead, early last fall, a friend reached out to me about an opening on her team at Salesforce. They wanted someone with an SRE background and security aspirations. Was I interested in pursuing it as a job, she asked, or was it just a professionally adjacent hobby?&lt;/p&gt;

&lt;p&gt;I had to sit and think about that.&lt;/p&gt;

&lt;p&gt;For about five seconds.&lt;/p&gt;

&lt;p&gt;I typed back a quick &lt;del&gt;I VOLUNTEER AS TRIBUTE&lt;/del&gt; extremely casual and professional confirmation that I was indeed interested in security as a career, and then the process began in earnest.&lt;/p&gt;

&lt;h3&gt;
  
  
  Starting the conversation, completing the interview
&lt;/h3&gt;

&lt;p&gt;My interview and hiring process, from first conversation to gauge interest to phone screen to final interview, took about two months. (This was longer than is typical for this role, as I was out of town for three weeks when I first applied.) I have an eclectic resume, as you’ll learn later, and, during my interview process with Salesforce, I got to highlight things that I have learned in different ways: through casual conversations, the formal interview, and even some impromptu network diagramming on a whiteboard when I realized my hand gestures were not up to conveying the complexity of what we were discussing. (Spoiler alert for preparing for a security interview, which I’ll talk much more about later in this post: if in doubt, it’s always the &lt;a href="https://owasp.org/www-project-top-ten/"&gt;OWASP Top Ten&lt;/a&gt;. Also worth checking out: &lt;a href="https://trailhead.salesforce.com/en/content/learn/trails/navigate-the-salesforce-hiring-process"&gt;Salesforce’s interviewing trail&lt;/a&gt;.) I was also able to meet a DevOps architect who, like me, thinks it’s extremely important to encourage junior engineers, which gave me a good feeling about Salesforce being a place I could be supported to successfully make the move into AppSec. We benefit enormously from diverse experience, so I was glad to know I was being assessed on my skills, not my years on the job or other sometimes-superficial markers of seniority. When I left after the interview, I wasn’t certain if I’d done well or not, but I felt like I’d done as well as I could have and demonstrated the things I actually know, which is a good interview in my book.&lt;/p&gt;

&lt;h3&gt;
  
  
  An ops CV for security
&lt;/h3&gt;

&lt;p&gt;I began my career as a writer and editor. I attended code school in 2015, and my first engineering job was at a consultancy that focused on infrastructure and process. After three years of consulting, I moved to a role as a site reliability engineer (SRE). Throughout all this, I cultivated my interest in security by going to &lt;a href="https://defcon.org/"&gt;DEF CON&lt;/a&gt;, &lt;a href="https://www.wisporg.com/"&gt;Women in Security and Privacy&lt;/a&gt; (WISP), &lt;a href="https://www.dayofshecurity.com/"&gt;Day of Shecurity&lt;/a&gt;, and the many other security events that take place in the Bay Area. It became clear pretty quickly that ops and security have a lot of things in common – that is, beyond a reputation for being risk-averse and more than a little curmudgeonly.&lt;/p&gt;

&lt;p&gt;There are skills that are essential for both, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Networking, infrastructure, AWS, and port hygiene&lt;/li&gt;
&lt;li&gt;Coding, especially scripting; Bash and Python are great choices but aren’t the only valid ones&lt;/li&gt;
&lt;li&gt;Command line skills&lt;/li&gt;
&lt;li&gt;Looking up running processes and changing their state&lt;/li&gt;
&lt;li&gt;Reading and manipulating logs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The skills that are less explicitly required but that I’ve found to be really useful include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Communication, both written and verbal&lt;/li&gt;
&lt;li&gt;Documentation creation and maintenance&lt;/li&gt;
&lt;li&gt;Teaching&lt;/li&gt;
&lt;li&gt;A UX-centered approach&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here’s what I mean by that last one: I have some education in UX principles and practices, and I’ve done official UX exercises as part of previous jobs. I’m still able to, if needed. The part of it I use most often, though, is what I’ve come to think of as a UX approach to the everyday. (&lt;a href="https://en.wikipedia.org/wiki/Shoshin"&gt;Beginner’s mind&lt;/a&gt; is a similar idea.) What I mean by that is the ability to come into a situation with someone and assume that you don’t understand their motivations, previous actions, or context, and then to work deliberately to build those by asking questions—while resisting the very normal human inclination to think that you totally understand this other person’s situation well before you actually understand it. The key part is remembering that, even if someone is doing something you don’t think makes sense, they most likely have reasons for it, and you can only discover those by asking them. &lt;/p&gt;

&lt;p&gt;This was useful in ops, when I was often dealing with app engineers who weren’t familiar with my part of our systems, and it’s useful in security, when an incomplete understanding of why people do what they do can result in processes that no one will use and vulnerabilities left unchecked. It makes you nicer to deal with, yes, but also much more effective in your work. &lt;/p&gt;

&lt;h3&gt;
  
  
  My accidental security education
&lt;/h3&gt;

&lt;p&gt;Here’s something I only realized after getting this job: I’ve done a LOT of security learning since becoming an engineer. I just didn’t fully realize what I’d been doing because I thought of it as just having fun. Meaning: I did none of these things with interview preparation in mind. The closest I came was thinking, “Oh, I see how this might be useful for the kinds of jobs I might want later, but I’m definitely not pursuing them right now.” It’s a great way to get an education in something, with no pressure and all of the enthusiasm of the hobbyist, but I realize it’s not going to be accessible for everyone. &lt;/p&gt;

&lt;p&gt;These are the things I did over the last four years that ended up being really helpful as I went through this process: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Going to DEF CON four times&lt;/li&gt;
&lt;li&gt;Going to &lt;a href="https://www.dayofshecurity.com/"&gt;Day of Shecurity&lt;/a&gt; three times&lt;/li&gt;
&lt;li&gt;Being a beta student for an eight-part course all about writing secure code from &lt;a href="https://www.goldhatsecurity.com/"&gt;a friend’s security education startup&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Attempting &lt;a href="https://ctf101.org/"&gt;Capture the Flags&lt;/a&gt; (CTFs) &lt;/li&gt;
&lt;li&gt;Talking security with my ops coworkers, who all have opinions and stories&lt;/li&gt;
&lt;li&gt;Volunteering for &lt;a href="https://aws.amazon.com/iam/"&gt;AWS IAM&lt;/a&gt; work whenever it came up as a task&lt;/li&gt;
&lt;li&gt;Classes at the &lt;a href="https://bradfieldcs.com/"&gt;Bradfield School of Computer Science&lt;/a&gt; in computer architecture and networking (I suggest getting a company to pay for this)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every one of these things gave me something that either helped me feel more adept while interviewing or that I was able to mention when answering questions and discussing the job. Four years is a lot of time to pursue something casually, especially since I went to an event at least every month or two. &lt;/p&gt;

&lt;p&gt;I’ve also benefited from industry newsletters, especially these:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;a href="https://cloudseclist.com/"&gt;Cloud Security Reading List&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Julia Evans’s weekly emailed &lt;a href="https://jvns.ca/newsletter/"&gt;engineering comics&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.devopsweekly.com/"&gt;Devops Weekly&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://sreweekly.com/"&gt;SRE Weekly&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.schneier.com/crypto-gram/subscribe.html"&gt;Crypto-Gram&lt;/a&gt; from Bruce Schneier &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Many of these are ops-centric, but all of them have provided something to this most recent professional transition. Very few issues and problems exist in only a single discipline, and these digests have been really useful for seeing the regular intersections between things I knew and things I wanted to know more about.&lt;/p&gt;

&lt;h3&gt;
  
  
  Interview preparation, done deliberately
&lt;/h3&gt;

&lt;p&gt;Once the interview was scheduled, I dove into interview studying. I made a wishlist of everything I wanted to be able to talk confidently about, prioritized it, and began working through everything I could. I touched on about half of it, as it was an ambitious list. I studied for about a week and a half, a couple hours at a time. I focused on three main things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://exercism.io/"&gt;Exercism&lt;/a&gt;, primarily in Python&lt;/li&gt;
&lt;li&gt;The &lt;a href="https://owasp.org/www-project-top-ten/?cm_mc_uid=38435500426614997887726&amp;amp;cm_mc_sid_50200000=1499793883&amp;amp;cm_mc_sid_52640000=1499793883"&gt;OWASP top ten from 2013&lt;/a&gt; and &lt;a href="https://owasp.org/www-project-top-ten/OWASP_Top_Ten_2017/Top_10-2017_Top_10"&gt;2017&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Blog posts that crossed my current discipline and the one I aspired to&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Exercism work was because I never feel like I code as much as I’d like in my jobs, and I feel more confident in technical settings when I feel more fluent in code. The OWASP reading was a mix of official resources, their cheat sheets, and other people’s writing about them; reading different perspectives is part of how I wrap my head around things like this. And the blog posts were for broader context and also to get more conversant about the intersection between my existing skills and the role I was aspiring to. Studying a high-profile breach that happened due to misconfigured AWS IAM permissions, something I was already well versed in, was really useful for this. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;(Read about our open source project &lt;a href="https://engineering.salesforce.com/salesforce-cloud-security-automating-least-privilege-in-aws-iam-with-policy-sentry-b04fe457b8dc"&gt;Policy Sentry&lt;/a&gt; automates least privilege in AWS IAM.)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Here’s a &lt;a href="https://gist.github.com/breanneboland/42372de3bb60dc89ec4d893fdd2be2ce"&gt;grab bag&lt;/a&gt; of some of the other things I read, watched, and used that helped me feel better prepared for the interview.&lt;/p&gt;

&lt;p&gt;The great and terrible thing about infosec education is that there are so many resources out there for you to learn from. Pick a couple of things you want to get really good at (ideally that you already know something about, that’s already important to your current job or field of study) and keep digging into them. The other thing I’d recommend, which I hear suggested less often, is making sure you can explain what it is you’re trying to understand to another person. I have a couple non-engineer people in my life who let me explain things to/at them, and it’s the single best thing I do to make sure I actually understand something, instead of that inaccurate feeling of “understanding” that actually means “I read that, and the individual sentences made sense,” which is a bit different - and not something you want to realize in the middle of an onsite. &lt;/p&gt;

&lt;h3&gt;
  
  
  No, really: you can too
&lt;/h3&gt;

&lt;p&gt;I want to leave you with some more general ideas of how to shape your career to more effectively get to the security role you might be seeking.&lt;/p&gt;

&lt;p&gt;Find a couple security-essential skills you already know something about and dive deeply into them. For instance: I have a lot to say about IAM stuff, in AWS, Jenkins, and general principle of least privilege contexts, so that’s been something I’ve really focused on when trying to convey my skills to other people. Find what you’re doing that already applies to the role you want, and get conversational in it. Keep up on news stories relevant to those skills. This part shouldn’t be that hard, because these skills should be interesting to you. If they aren’t, choose different skills to focus on, and keep that in mind as you continue figuring out the right place for you in security.&lt;/p&gt;

&lt;p&gt;While you’re doing this learning, make sure the people in your professional life know what you’re doing. This can be your manager, but it can also be online communities, coworkers you keep in touch with as you all move companies, and anyone else you can speak computer or security with. Don’t labor in obscurity; share links, mention things you’ve learned, and search for other people interested in the same things.&lt;/p&gt;

&lt;p&gt;Build that community further by going to meetups and workshops. When I think about living outside the Bay Area, one of the things that would be hardest to give up is all the free education that’s available. &lt;a href="https://www.dayofshecurity.com/"&gt;Day of Shecurity&lt;/a&gt;, &lt;a href="https://www.meetup.com/Bay-Area-OWASP/"&gt;OWASP&lt;/a&gt; in SF and the &lt;a href="https://www.meetup.com/NCCOpenForumSF/"&gt;south bay&lt;/a&gt; and so many more—and with everything being online now, there are so many more resources available from wherever you live. Follow some infosec folks on Twitter, search on &lt;a href="http://meetup.com/"&gt;meetup.com&lt;/a&gt;, and find your people. &lt;/p&gt;

&lt;p&gt;Finally, remember that security needs you. Like all of tech, security is better when there are a lot of different kinds of people working out how to make things and fix things. Please hang in there and keep trying. And good luck. &amp;lt;3&lt;/p&gt;

</description>
      <category>career</category>
      <category>security</category>
      <category>sre</category>
    </item>
    <item>
      <title>How to Build a VS Code extension for Markdown preview using Remark processor</title>
      <dc:creator>Laura Lindeman</dc:creator>
      <pubDate>Tue, 13 Oct 2020 13:31:22 +0000</pubDate>
      <link>https://dev.to/salesforceeng/how-to-build-a-vs-code-extension-for-markdown-preview-using-remark-processor-1169</link>
      <guid>https://dev.to/salesforceeng/how-to-build-a-vs-code-extension-for-markdown-preview-using-remark-processor-1169</guid>
      <description>&lt;h3&gt;
  
  
  Add missing remark preview support by writing your own extension.
&lt;/h3&gt;

&lt;h3&gt;
  
  
  Author:
&lt;/h3&gt;

&lt;p&gt;Subrat Thakur (&lt;a href="//mailto:subrat.thakur@salesforce.com"&gt;subrat.thakur@salesforce.com&lt;/a&gt;)&lt;br&gt;
LinkedIn: &lt;a href="https://www.linkedin.com/in/subrat-thakur/" rel="noopener noreferrer"&gt;https://www.linkedin.com/in/subrat-thakur/&lt;/a&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Visual Studio Code (VS Code) is a cross-platform, light-weight code editor created by Microsoft for Linux, Windows, and macOS. VS Code has support for extensions to add extra capabilities. If a feature you want is missing, you can create an extension to add it. &lt;/p&gt;

&lt;p&gt;In my case, I wanted to be able to use a Markdown processor other than the one natively supported by VS Code. VS Code supports Markdown files out of the box and targets the &lt;a href="https://commonmark.org/" rel="noopener noreferrer"&gt;CommonMark&lt;/a&gt; Markdown specification using the &lt;a href="https://github.com/markdown-it/markdown-it" rel="noopener noreferrer"&gt;markdown-it&lt;/a&gt; library. But there is no way to use another markdown processor like &lt;a href="https://github.com/remarkjs/remark" rel="noopener noreferrer"&gt;remark&lt;/a&gt;, &lt;a href="https://github.com/commonmark/commonmark.js" rel="noopener noreferrer"&gt;common marker&lt;/a&gt;, or showdown instead of markdown-it in default preview. You can definitely change the style by adding CSS to update the look and feel but the internal processor will stay as markdown-it. So, I decided to create my first VS Code extension! In addition to sharing this specific extension in the Marketplace, I wanted to outline the steps I took to build it, so that you can build an extension for a feature you want to see.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ffdw65feofxho3r492r1m.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ffdw65feofxho3r492r1m.gif" alt="Markdown Previewer" width="282" height="168"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  The very first step of building a VS Code Extension
&lt;/h2&gt;

&lt;p&gt;To get started, install the following if you haven’t already:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://code.visualstudio.com/download" rel="noopener noreferrer"&gt;VS Code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nodejs.org/en/" rel="noopener noreferrer"&gt;Node.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://yeoman.io/" rel="noopener noreferrer"&gt;Yeoman&lt;/a&gt;: An open-source client-side scaffolding tool that helps you kickstart new projects.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/Microsoft/vscode-generator-code" rel="noopener noreferrer"&gt;vscode-generator-code&lt;/a&gt;: A Yeoman generator to generate a new Visual Studio Code extension project from a template.&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;To install Yeoman and vscode-generator-code&lt;/code&gt;: &lt;code&gt;npm install -g yo generator-code&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;VS Code extensions support two main languages: JavaScript and TypeScript. So having basic knowledge of either of these is pretty mandatory.&lt;/p&gt;
&lt;h2&gt;
  
  
  Generate a VS Code Extension Template
&lt;/h2&gt;

&lt;p&gt;Go To ‘Terminal’ (‘Command Prompt’ in case of Windows), navigate to the folder where you want to generate the extension, type the following command, and hit &lt;strong&gt;Enter&lt;/strong&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;yo code&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;At the prompt, you must answer some questions about your extension:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;What type of extension do you want to create?&lt;/strong&gt; New Extension (TypeScript).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fgt71iynuo0rm8g91457w.png" alt="List of extension types" width="800" height="256"&gt;&lt;/li&gt;
&lt;li&gt;To know about other type of extension you can go through : &lt;a href="https://code.visualstudio.com/api#what-can-extensions-do" rel="noopener noreferrer"&gt;What can extensions do ?&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;What’s the name of your extension?&lt;/strong&gt;  (in my case it was Remark Preview)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;What’s the identifier of your extension?&lt;/strong&gt;  (consider it Visible Name in small-case separated by -) e.g remark-preview&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;What’s the description of your extension?&lt;/strong&gt; Write something about your extension (you can fill this in or edit it later too).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Initialize a Git repository?&lt;/strong&gt; This initializes a Git repository, and you can add &lt;code&gt;set-remote&lt;/code&gt;later. To create an extension Git repo is not a mandatory thing. You can publish it directly from your local as well.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Which package manager to use?&lt;/strong&gt; You can choose yarn or npm; I will use npm.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hit the &lt;strong&gt;Enter&lt;/strong&gt; key, and it will start installing the required dependencies. And finally you will get:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Your extension remark-preview has been created!

To start editing with Visual Studio Code, use the following commands:

 cd remark-preview
 code .
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  The project's structure
&lt;/h2&gt;

&lt;p&gt;Once you are done with generating the extension template and open it in VS Code, your editor will look like this:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F4yb7m8ln9banof7rardr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F4yb7m8ln9banof7rardr.png" alt="Preview of editor at this stage" width="800" height="970"&gt;&lt;/a&gt;&lt;br&gt;
The generator-code project creates the most basic wiring and plumbing needed for a functioning extension. If you look in the extension directory, you’ll see several files:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;vsc-extension-quickstart.md&lt;/strong&gt; provides some instructions for creating and using the extension.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;extension.js&lt;/strong&gt; is the actual code for the extension. The entire extension doesn’t need to fit into this one file, but this is the default entry point for the extension.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;jsconfig.json&lt;/strong&gt; controls how the project’s JavaScript code is handled by the Node.js runtime. You generally don’t need to change anything here.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;package.json&lt;/strong&gt; contains the packaging information for your extension. If you are a Node.js developer, some of this might look familiar since &lt;code&gt;name&lt;/code&gt;, &lt;code&gt;description&lt;/code&gt;, &lt;code&gt;version&lt;/code&gt;, and &lt;code&gt;scripts&lt;/code&gt;&lt;strong&gt;&lt;code&gt;&lt;/code&gt;&lt;/strong&gt;are common parts of a Node.js project. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I will talk about the files more, but, for now, let’s try running our basic extension.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// This will install all the dependencies
npm install

// This will compile your code 
npm run compile

// Run the code by hitting f5
f5
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The above code instructions will open a new VS Code window with your basic extension installed in it.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fymr9vh6sc9cilg55rux2.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fymr9vh6sc9cilg55rux2.gif" alt="VS Code window with basic extension installed" width="668" height="500"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  What’s different inside Package.json ?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;There are a few sections that are very important.

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;engines&lt;/code&gt;: States which version of VSCodium the extension will support&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;categories&lt;/code&gt;: Sets the extension type; you can choose from &lt;strong&gt;Languages&lt;/strong&gt;, &lt;strong&gt;Snippets&lt;/strong&gt;, &lt;strong&gt;Linters&lt;/strong&gt;, &lt;strong&gt;Themes&lt;/strong&gt;, &lt;strong&gt;Debuggers&lt;/strong&gt;, &lt;strong&gt;Formatters&lt;/strong&gt;, &lt;strong&gt;Keymaps&lt;/strong&gt;, and &lt;strong&gt;Other&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;contributes&lt;/code&gt;: A list of commands that can be used to run with your extension&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;main&lt;/code&gt;: The entry point of your extension&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;activationEvents&lt;/code&gt;: Specifies when the activation event happens. Specifically, this dictates when the extension will be loaded into your editor. Extensions are lazy-loaded, so they aren't activated until an activation event occurs&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fxfdn7mzx6v80qjgasli5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fxfdn7mzx6v80qjgasli5.png" alt="Section of code displaying activation events" width="800" height="858"&gt;&lt;/a&gt;&lt;br&gt;
Let’s focus on few &lt;strong&gt;concepts&lt;/strong&gt; that are crucial for VS Code extension development:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://code.visualstudio.com/api/references/activation-events" rel="noopener noreferrer"&gt;Activation Events&lt;/a&gt;: events upon which your extension becomes active. This will be part of &lt;strong&gt;package.json&lt;/strong&gt; e.g
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//the extension becomes activated when user runs the `Hello World` command
"activationEvents": [
  "onCommand:opendocs.helloWorld"
],
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This is currently there inside your newly generated projects package.json&lt;/p&gt;

&lt;p&gt;A few more example would be:&lt;br&gt;
EX 1:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//This activation event is emitted and interested extensions will be activated 
// whenever a file that resolves to a certain language gets opened.

"activationEvents": [
  "onLanguage:markdown"
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;blockquote&gt;
&lt;p&gt;As we are planning to develop an extension for markdown, the above could be suitable for our extension ⬆️&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;EX 2:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// This activation event is emitted and interested extensions will be activated 
// whenever a folder is opened and the folder contains at least one file 
// that matches a glob pattern. 
"activationEvents": [
  "workspacecontains: package.json"
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;EX 3:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//The `*` activation event is emitted and interested extensions will be activated 
// whenever VS Code starts up.
"activationEvents": [
  "*"
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;blockquote&gt;
&lt;p&gt;You can also provide multiple multiple event as "activationEvents" is an array.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;
  
  
  &lt;a href="https://code.visualstudio.com/api/references/contribution-points" rel="noopener noreferrer"&gt;Contribution Points&lt;/a&gt;
&lt;/h4&gt;

&lt;p&gt;Static declarations that you make in the package.json &lt;a href="https://code.visualstudio.com/api/get-started/extension-anatomy#extension-manifest" rel="noopener noreferrer"&gt;Extension Manifest&lt;/a&gt; to extend VS Code. This could be used to add commands available in command pallets, menu bar, editor title, editor context as well as configurations related to the extension.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://code.visualstudio.com/api/references/contribution-points#contributes.commands" rel="noopener noreferrer"&gt;Commands&lt;/a&gt;: Contribute the UI for a command consisting of a title and (optionally) an icon, category, and enabled state.&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://code.visualstudio.com/api/references/contribution-points#contributes.configuration" rel="noopener noreferrer"&gt;Configuration&lt;/a&gt;: Contribute configuration keys that will be exposed to the user. The user will be able to set these configuration options as User Settings or as Workspace Settings, either by using the Settings UI or by editing the JSON settings file directly.&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://code.visualstudio.com/api/references/contribution-points#contributes.menus" rel="noopener noreferrer"&gt;menus&lt;/a&gt;: Contribute a menu item for a command to the editor or Explorer. The menu item definition contains the command that should be invoked when selected and the condition under which the item should show.&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://code.visualstudio.com/api/references/contribution-points#contributes.keybindings" rel="noopener noreferrer"&gt;keybindings&lt;/a&gt;: Defining key binding for window (linux) and mac for each command.&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://code.visualstudio.com/api/references/contribution-points#Context-specific-visibility-of-Command-Palette-menu-items" rel="noopener noreferrer"&gt;Command Palette&lt;/a&gt;: When registering commands in package.json, they will automatically be shown in the Command Palette (⇧⌘P). To allow more control over command visibility, there is the command palette menu item. It allows you to define a when condition to control if a command should be visible in the Command Palette or not.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Sorting of groups: Menu items can be sorted into groups. The order inside a group depends on the title or an order-attribute. The group-local order of a menu item is specified by appending &lt;code&gt;@&amp;lt;number&amp;gt;&lt;/code&gt; to the group identifier&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  &lt;a href="https://code.visualstudio.com/api/extension-guides/command#registering-a-command" rel="noopener noreferrer"&gt;Registering a command&lt;/a&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://code.visualstudio.com/api/references/vscode-api#commands.registerCommand" rel="noopener noreferrer"&gt;vscode.commands.registerCommand&lt;/a&gt; binds a command id to a handler function in your extension. This will be part of extension.js by default (or whatever entry point you mentioned in package.json).&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Once you are done adding these few points your extension will be in good shape in terms of configuration. Let’s talk about our goal to generate a preview.&lt;/p&gt;

&lt;h2&gt;
  
  
  Generating Preview
&lt;/h2&gt;

&lt;p&gt;We already decided that we would use remark processor to process our markdown, but the most important question is: &lt;strong&gt;how are we going to show it inside VS Code?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;So the one word answer for it is &lt;strong&gt;&lt;a href="https://code.visualstudio.com/api/extension-guides/webview" rel="noopener noreferrer"&gt;Webview&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;What is Webview ?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;As per VS Code documentation, the webview API allows extensions to create fully customizable views within Visual Studio Code. For example, the built-in Markdown extension uses webviews to render Markdown previews. Think of a webview as an &lt;code&gt;iframe&lt;/code&gt; within VS Code that your extension controls. A webview can render almost any HTML content in this frame, and it communicates with extensions using message passing.&lt;/p&gt;

&lt;p&gt;So the flow is going to be very simple :&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create HTML of our Markdown content using remark.&lt;/li&gt;
&lt;li&gt;Add it to Webview as content.&lt;/li&gt;
&lt;li&gt;Show that Webview in VS Code!&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Simple, right?! I promise it is simpler than it sounds!&lt;/p&gt;

&lt;p&gt;SO, let’s begin.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create HTML content from Markdown content
&lt;/h3&gt;

&lt;p&gt;This code sample will turn markdown into HTML. In our case, instead of creating another Markdown compiler instance, we will use &lt;a href="https://www.npmjs.com/package/@sfdocs-internal/markdown-compiler" rel="noopener noreferrer"&gt;&lt;strong&gt;@sfdocs-internal/compiler&lt;/strong&gt;&lt;/a&gt; package .&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import admonitions from 'remark-admonitions';
import * as html from 'remark-html';
import * as remark from 'remark';

function markdownCompiler(): any {
    const admonitionsOptions = {};

    return remark()
        .use(html)
        .use(admonitions, admonitionsOptions);
}

let currentHTMLContent = await markdownCompiler().process(markdownContent);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You need to add the below entries to package.json and run npm install to install new dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;        "remark": "12.0.1",
        "remark-admonitions": "1.2.1",
        "remark-html": "12.0.0",
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Create a Webview Panel
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Create and show a new webview
this.panel = vscode.window.createWebviewPanel(
        // Webview id
        'liveHTMLPreviewer',
        // Webview title
        '[Preview] ' + fileName,
        // This will open the second column for preview inside editor
        2,
        {
            // Enable scripts in the webview
            enableScripts: true,
            retainContextWhenHidden: true,
            // And restrict the webview to only loading content from our extension's `assets` directory.
            localResourceRoots: [vscode.Uri.file(path.join(this.context.extensionPath, 'assets'))]
        }
 );
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Add HTML to Webview Content
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;this.panel.webview.html = await markdownCompiler().process(markdownContent);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, this is what your extension.ts should look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import * as vscode from 'vscode';
import { admonitions } from 'remark-admonitions';
import * as html from 'remark-html';
import * as remark from 'remark';
import * as path from 'path';


export function activate(context: vscode.ExtensionContext) {

    // commandId
    const SIDE_PREVIEW_COMMAND = 'remark.sidePreview';

    const disposableSidePreview = vscode.commands.registerCommand(SIDE_PREVIEW_COMMAND, async () =&amp;gt; {
        initMarkdownPreview(context);
    });

    context.subscriptions.push(disposableSidePreview);
}

async function initMarkdownPreview(context: vscode.ExtensionContext) {
    const panel = vscode.window.createWebviewPanel(
        // Webview id
        'liveHTMLPreviewer',
        // Webview title
        '[Preview]',
        // This will open the second column for preview inside editor
        2,
        {
            // Enable scripts in the webview
            enableScripts: true,
            retainContextWhenHidden: true,
            // And restrict the webview to only loading content from our extension's `assets` directory.
            localResourceRoots: [vscode.Uri.file(path.join(context.extensionPath, 'assets'))]
        }
    );
    panel.webview.html = await markdownCompiler().process(vscode.window.activeTextEditor?.document.getText());
}

function markdownCompiler(): any {
    const admonitionsOptions = {};
    return remark()
        .use(html)
        .use(admonitions, admonitionsOptions);
}



// this method is called when your extension is deactivated
export function deactivate() { }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can make it more modular and efficient.&lt;/p&gt;

&lt;p&gt;Now let’s talk about few more things that might be useful for your new preview extension.&lt;/p&gt;




&lt;h3&gt;
  
  
  Developer Tools for Webview
&lt;/h3&gt;

&lt;p&gt;As I already told you, Webview is very similar to a Web Browser; you can actually inspect the Webview Panel, check the console logs, and debug any script added to it when the Webview is open. To do all this, open Command Palette (⇧⌘P) and Search for “&lt;strong&gt;Developer: Open Webview Developer Tools.&lt;/strong&gt;” This will open a developer console very similar to Chrome browser. &lt;/p&gt;

&lt;h3&gt;
  
  
  Content security policy for Webview
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://developers.google.com/web/fundamentals/security/csp/" rel="noopener noreferrer"&gt;Content security policies&lt;/a&gt; further restrict the content that can be loaded and executed in webviews.&lt;/p&gt;

&lt;p&gt;To add a content security policy, put a &lt;code&gt;&amp;lt;meta http-equiv="Content-Security-Policy"&amp;gt;&lt;/code&gt; directive at the top of the webview's &lt;code&gt;&amp;lt;head&amp;gt;.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Here's a content security policy that allows loading local scripts and stylesheets (inline as well), and loading images over &lt;code&gt;https&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src ${panel.webview.cspSource} 'self' 'unsafe-inline'; script-src 'nonce-${nonce}'; style-src ${panel.webview.cspSource} 'self' 'unsafe-inline'; font-src ${panel.webview.cspSource}"&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;${webview.cspSource}&lt;/code&gt; value is a placeholder for a value that comes from the webview object itself.&lt;/p&gt;

&lt;p&gt;We can also load the scripts and css in old fashion way if we use vscode uri path instead of relative path.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function **getDynamicContentPath**(context, panel, filepath) {
    const onDiskPath = vscode.Uri.file(path.join(context.extensionPath, filepath))
    const styleSrc = panel.webview.asWebviewUri(onDiskPath);
    return styleSrc
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;VS Code creates a secure URI for webview panel and makes it accessible for Iframe.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;link rel="stylesheet" type="text/css" href="${getDynamicContentPath(context, panel, 'assets/css/admonitions.css')}"&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  How to interact with Webview through Messages?
&lt;/h3&gt;

&lt;p&gt;As we all know by now, Webview is content inside an iframe, so we need special messaging to send events to Webview.&lt;br&gt;
So whenever we want to send a message we can use something similar to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;private postMessage(msg: any) {
        // here this flag is to check if webview panel is still alive or not
        if (!this._disposed) {

        // this.panel is the instance of Webview Panel
            this.panel.webview.postMessage({
                        type: 'messageFromExtension',
                        line: visibleRanges});
        }
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let’s see how to catch this message inside Webview. The most important thing is that this script should be part of the HTML that we add to Webview panel.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;window.addEventListener('message', event =&amp;gt; {
    const message = event.data;
    if (message.type === 'messageFromExtension') {
        console.log('Line : ' + message.line[0][0].line);
        onUpdateView(per);
    }
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In a very similar fashion, we can catch any window event of Webview as well like scroll, click, double click, etc.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;window.addEventListener('scroll', throttle(() =&amp;gt; {
    console.log("Scroll Event in Webview window");
}, 100));
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To send any message back to VS Code, we need to use &lt;code&gt;acquireVsCodeApi&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// acquireVsCodeApi is the api to talk to extension from webview
const vscode = acquireVsCodeApi();

// createPosterForVsCode is a class provided by VSCode
const messaging = createPosterForVsCode(vscode);
messaging.postMessage('revealLine', { line });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And in the same way, we need a subscribe method for any events coming from Webview:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//this should be part of extension and no need to load inside webview
this.panel.webview.onDidReceiveMessage(e =&amp;gt; {
     console.log(e.body.line);
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  Publishing Extensions
&lt;/h1&gt;

&lt;p&gt;To publish an extension, you need to set up a few things.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Install &lt;a href="https://code.visualstudio.com/api/working-with-extensions/publishing-extension#vsce" rel="noopener noreferrer"&gt;VSCE&lt;/a&gt; : &lt;a href="https://github.com/microsoft/vsce" rel="noopener noreferrer"&gt;vsce&lt;/a&gt;, short for "Visual Studio Code Extensions," is a command-line tool for packaging, publishing and managing VS Code extensions. You can use &lt;code&gt;vsce&lt;/code&gt; to easily &lt;a href="https://code.visualstudio.com/api/working-with-extensions/publishing-extension#packaging-extensions" rel="noopener noreferrer"&gt;package&lt;/a&gt; and &lt;a href="https://code.visualstudio.com/api/working-with-extensions/publishing-extension#publishing-extensions" rel="noopener noreferrer"&gt;publish&lt;/a&gt; your extensions. It can also search, retrieve metadata, and unpublish extensions.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;To install VSCE:       &lt;strong&gt;npm install -g vsce&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://code.visualstudio.com/api/working-with-extensions/publishing-extension#get-a-personal-access-token" rel="noopener noreferrer"&gt;Get a Personal Access Token&lt;/a&gt;: You need to create an account on &lt;a href="https://login.microsoftonline.com/common/oauth2/authorize?client_id=499b84ac-1321-427f-aa17-267ca6975798&amp;amp;site_id=501454&amp;amp;response_mode=form_post&amp;amp;response_type=code+id_token&amp;amp;redirect_uri=https%3A%2F%2Fapp.vssps.visualstudio.com%2F_signedin&amp;amp;nonce=1e7a8620-e8c8-4d45-8a70-bf769ad903b1&amp;amp;state=realm%3Daex.dev.azure.com%26reply_to%3Dhttps%253A%252F%252Faex.dev.azure.com%252Fsignup%253FacquisitionId%253Dd1048ee8-c23e-49e5-8f1c-5749010b2f43%2526campaign%253Dacom~azure~devops~services~main~hero%2526githubsi%253Dtrue%2526WebUserId%253D11FEF0CEF2C7684C09D4FFFEF36C6924%2526acquisitionType%253DbyDefault%26ht%3D3%26nonce%3D1e7a8620-e8c8-4d45-8a70-bf769ad903b1&amp;amp;resource=https%3A%2F%2Fmanagement.core.windows.net%2F&amp;amp;cid=1e7a8620-e8c8-4d45-8a70-bf769ad903b1&amp;amp;wsucxt=1&amp;amp;githubsi=true&amp;amp;msaoauth2=true" rel="noopener noreferrer"&gt;Azure Dev&lt;/a&gt;. You can log in using Github as well. Once you log in, you have to create a project; you can probably name it VSCode Extensions. Once you are done, let’s move ahead to create Personal Access Token.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Open the User settings dropdown menu next to your profile image (top right corner) and select Personal access tokens:&lt;/li&gt;
&lt;li&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F1tmtuazzyu39yiepy5oj.png" alt="User settings dropdown menu indicating where to select Personal access tokens" width="520" height="824"&gt;&lt;/li&gt;
&lt;li&gt;On the Personal Access Tokens page, click &lt;strong&gt;New Token&lt;/strong&gt; to create a new Personal Access Token&lt;/li&gt;
&lt;li&gt;Give the Personal Access Token a name; optionally, you can extend its expiration date to one year, make it accessible to every organization, or select a custom defined scope ruleset:&lt;/li&gt;
&lt;li&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F2tdayvuetx948c72ccvy.png" alt="Options to select when saving your Personal Access Token" width="800" height="693"&gt;&lt;/li&gt;
&lt;li&gt;Finally, &lt;strong&gt;scroll down&lt;/strong&gt; the list of possible scopes until you find &lt;strong&gt;Marketplace&lt;/strong&gt; and select Manage:&lt;/li&gt;
&lt;li&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F7w3z598motmj0f5bjdxl.png" alt="Managing scopes for your Personal Access Token" width="800" height="773"&gt;&lt;/li&gt;
&lt;li&gt;Select Create and you'll be presented with your newly created Personal Access Token. &lt;strong&gt;Copy it&lt;/strong&gt;; you'll need it to create a publisher.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Create a publisher : A publisher is an identity that can publish extensions to the Visual Studio Code Marketplace. Every extension needs to include a &lt;code&gt;publisher&lt;/code&gt; name in its &lt;a href="https://code.visualstudio.com/api/references/extension-manifest" rel="noopener noreferrer"&gt;&lt;code&gt;package.json&lt;/code&gt; file&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;

&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Use this command to create publisher :    &lt;strong&gt;vsce create-publisher &lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;Log in to a publisher: This is a one-time task and requires your publisherId and Personal Access Token.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Use this command to login :    &lt;strong&gt;vsce login &lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;Publish your extension: As the final step, publish your extension to marketplace.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Use this command to publish :    &lt;strong&gt;vsce publish&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Keep in mind you always need to change version in package.json before re-publishing the extension, or else it will throw an error. You can use a command like &lt;code&gt;vsce publish minor&lt;/code&gt; or &lt;code&gt;vsce publish 2.0.1&lt;/code&gt; .&lt;/p&gt;

&lt;h1&gt;
  
  
  Wrapping up
&lt;/h1&gt;

&lt;p&gt;One message I want you to take to heart is that creating a VSCode extension is &lt;strong&gt;not as hard as it looks. It is pretty simple, actually.&lt;/strong&gt; Sometimes you just need to push yourself a bit and try things out.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;VS Code is awesome&lt;/strong&gt; 😎 and it’s really amazing how we can extend functionality inside it by developing extensions.&lt;br&gt;
There are many helpful APIs that will help you create the extensions you want to build. The VS Code extension API has many other powerful methods you can use.&lt;/p&gt;

&lt;p&gt;If you want to take a look at the whole project the code is available &lt;a href="https://github.com/SubratThakur/remark-preview" rel="noopener noreferrer"&gt;&lt;strong&gt;here&lt;/strong&gt;&lt;/a&gt;, which might help for code references (watch out for some messy code though!) and you can also find it in the &lt;a href="https://marketplace.visualstudio.com/items?itemName=SubratThakur.remark-preview" rel="noopener noreferrer"&gt;&lt;strong&gt;marketplace&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reference
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/microsoft/vscode-extension-samples" rel="noopener noreferrer"&gt;VS Code Extension Sample&lt;/a&gt;&lt;br&gt;
&lt;a href="https://code.visualstudio.com/api/extension-guides/overview" rel="noopener noreferrer"&gt;VS Code Extension DOC&lt;/a&gt;&lt;br&gt;
&lt;a href="https://code.visualstudio.com/api/extension-capabilities/overview#workbench-extensions" rel="noopener noreferrer"&gt;Workbench Extension&lt;/a&gt;&lt;/p&gt;

</description>
      <category>vscode</category>
      <category>howto</category>
      <category>markdown</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Salesforce Standup with Jae Taylor</title>
      <dc:creator>Laura Lindeman</dc:creator>
      <pubDate>Mon, 28 Sep 2020 18:43:47 +0000</pubDate>
      <link>https://dev.to/salesforceeng/salesforce-standup-with-jae-taylor-hn0</link>
      <guid>https://dev.to/salesforceeng/salesforce-standup-with-jae-taylor-hn0</guid>
      <description>&lt;p&gt;&lt;em&gt;Welcome to the Salesforce Standup, where we check in with employees in our Technology, Marketing, and Product organization from locations all over the world! At every Standup we ask our guest some questions to help us get to know them better. As any good standup should be, it's a quick chat where we’ll find out answers the questions that matter most—or maybe are just the most fun. You’ll have to watch to find out.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Today's guest, Jae Taylor, is a director of Product Management for Service Delivery at Salesforce. That means he drives the efforts to make sure our platform, which so many people depend on, is highly available and highly performant.&lt;/p&gt;

&lt;p&gt;Outside of work, Jae is passionate about the importance of mentorship, which he's seen at play throughout his varied career. He's not a morning person but has started running first thing and finds it makes him more alert and productive throughout the day. And, he loves spending time with his kids building video games.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--EkmbnQEb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ng8xmxc5l1kf12fm9w8o.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--EkmbnQEb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ng8xmxc5l1kf12fm9w8o.jpg" alt="Jae is pictured with his wife and four children."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Catch the whole interview to find out more about Jae!&lt;/p&gt;



&lt;blockquote class="twitter-tweet"&gt;
&lt;br&gt;
&lt;p&gt;We caught up with &lt;a href="https://twitter.com/JaeInTech?ref_src=twsrc%5Etfw"&gt;@JaeInTech&lt;/a&gt; in the latest edition of the &lt;a href="https://twitter.com/hashtag/SalesforceStandup?src=hash&amp;amp;ref_src=twsrc%5Etfw"&gt;#SalesforceStandup&lt;/a&gt;. He loves Korean food, building games with his kids in &lt;a href="https://twitter.com/unity3d?ref_src=twsrc%5Etfw"&gt;@unity3d&lt;/a&gt;, and starting his day on his &lt;a href="https://twitter.com/onepeloton?ref_src=twsrc%5Etfw"&gt;@onepeloton&lt;/a&gt; treadmill! Watch the video to learn what new gadget has changed the way he uses his phone pic.twitter.com/AGhR65IsYG&lt;/p&gt;— @SalesforceEng (@SalesforceEng) &lt;a href="https://twitter.com/SalesforceEng/status/1309515251516420096?ref_src=twsrc%5Etfw"&gt;September 25, 2020&lt;/a&gt;&lt;br&gt;
&lt;/blockquote&gt; 

</description>
      <category>career</category>
    </item>
  </channel>
</rss>
