<?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>Forem: Zach Peters</title>
    <description>The latest articles on Forem by Zach Peters (@zpeters).</description>
    <link>https://forem.com/zpeters</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%2Fuser%2Fprofile_image%2F106630%2F18bdfd79-e314-4d59-bb75-63c78a88689a.jpeg</url>
      <title>Forem: Zach Peters</title>
      <link>https://forem.com/zpeters</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/zpeters"/>
    <language>en</language>
    <item>
      <title>Testing in Go with table drive tests and Testify</title>
      <dc:creator>Zach Peters</dc:creator>
      <pubDate>Mon, 26 Oct 2020 13:43:39 +0000</pubDate>
      <link>https://forem.com/zpeters/testing-in-go-with-table-drive-tests-and-testify-kd4</link>
      <guid>https://forem.com/zpeters/testing-in-go-with-table-drive-tests-and-testify-kd4</guid>
      <description>&lt;p&gt;(Originally posted at &lt;a href="https://thehelpfulhacker.net/posts/2020-10-13-golang-testify-table-tests/"&gt;https://thehelpfulhacker.net/posts/2020-10-13-golang-testify-table-tests/&lt;/a&gt;)&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing in Go
&lt;/h2&gt;

&lt;p&gt;Over the past years of using Go on and off I have slowly settled on a few things for testing.  I am by no means a rigorous TDD developer, but I have been trying to make testing more and more a part of my normal code.&lt;/p&gt;

&lt;p&gt;I try to pick bits and pieces of different testing best practices, but the one thing I know about myself as a developer is that if it feels overly complicated at the moment there is a good chance I will skip it. The other thing I have learned is that I tend to start out with proof-of-concept "throw away" code for my prototypes and then spend a lot of time and gain some frustration trying to build that into a more stable/production type system.&lt;br&gt;&lt;br&gt;
Below are my notes on how I build up a "low impact" testing scenario from the beginning that is flexibile further down the road.  The key to testing is trust and if you can trust your tests early on it gives you to confidence to iterate with less fear of breaking &lt;em&gt;something&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Nothing below will be arcane or earth-shattering, just some personal notes to save some time googling and maybe the seeds of an idea for another developer&lt;/p&gt;
&lt;h2&gt;
  
  
  "Normal" tests
&lt;/h2&gt;

&lt;p&gt;Before we jump into table testing I wanted to write a very quick refresher on testing - in general - in Go.  In Go, we like to follow a few conventions.  When I started this did feel a bit messy and scattered to me.  I was used to languages like Elixir where it is more conventional to keep all of your tests in a &lt;em&gt;test&lt;/em&gt; folder.  The side-effect of this, at least in my mind, was to always think of tests as something opitonal that lives "to the side" of your code. This encourages lazy habits for me. Out of sight, out of mind... &lt;/p&gt;

&lt;p&gt;In Go things are different, at least if you follow the common conventions.  In Go your tests will normally live in a file in the same folder as your code named with an &lt;em&gt;_test.go&lt;/em&gt;.  For example, &lt;em&gt;mylib.go&lt;/em&gt; would have a corresponding test file called &lt;em&gt;mylib_test.go&lt;/em&gt;.  Again, to me this seemed cluttered in the beginning.  As I got used to it, it really did help me switch mentally to the thought that my tests and code are one "thing".  Also, if i see that i do not have any &lt;em&gt;_test&lt;/em&gt; files I know right away that some work needs to be done.&lt;/p&gt;

&lt;p&gt;Now that we have the file &lt;em&gt;naming&lt;/em&gt; out of the way I will show you the most basic example of code and the corresponding tests.  I will leave some links that explain testing in Go much better then I will.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;mylib.go&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;package&lt;/span&gt; &lt;span class="n"&gt;mylib&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="s"&gt;"fmt"&lt;/span&gt;    

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;MyFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;out&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;err&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;out&lt;/span&gt; &lt;span class="o"&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;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello: %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;in&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;out&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;&lt;strong&gt;mylib_test.go&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;package&lt;/span&gt; &lt;span class="n"&gt;mylib&lt;/span&gt;

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

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;TestMyFunction&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;out&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;MyFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Bob"&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;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Should not get an error"&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;out&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="s"&gt;"Hello: Bob"&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;"Should have gotten expected output"&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;Really this is great. It's simple and to the point.  You can get a &lt;em&gt;ton&lt;/em&gt; of mileage out of just this format. Get some output, maybe check for errors and check that the error is what you expect.  It &lt;em&gt;is&lt;/em&gt; Go so you can make this testing or comparison as elaborate or simple as you like. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;Additional reading on testing in Go&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://golang.org/pkg/testing/"&gt;https://golang.org/pkg/testing/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://gobyexample.com/testing"&gt;https://gobyexample.com/testing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.golang-book.com/books/intro/12"&gt;https://www.golang-book.com/books/intro/12&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Table driven tests
&lt;/h2&gt;

&lt;p&gt;Over time, using the techinique above, you will start to develope some routines and common patterns.  In Go, there are many things that lead to "boilerplat" code.  The best example is the &lt;code&gt;if err != nil&lt;/code&gt; convention of handling errors.  You are free to continue to write this, or you may wish to reduce your code and create a generic handling function.&lt;/p&gt;

&lt;p&gt;Much like this you can imagine testing the same function over and over again with differnt inputs could become tiresome.  This brings us to table driven tests!&lt;/p&gt;

&lt;p&gt;The main idea is that we can write the &lt;em&gt;general&lt;/em&gt; code once and only vary the parts that change.  Through a few common Go idioms we can create a powerful testing "framework" that is easy to elaborate on.  More importantly, it is easy to read &lt;em&gt;and&lt;/em&gt; reason about.&lt;/p&gt;

&lt;p&gt;Let's imagine the same scenario above. In "table testing" format it would look something like this.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;mylib_test.go&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;package&lt;/span&gt; &lt;span class="n"&gt;mylib&lt;/span&gt;

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

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;TestMyFunction&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;// myTests is a slice of structs&lt;/span&gt;
    &lt;span class="c"&gt;// The struct holds our inputs and expected outputs&lt;/span&gt;
    &lt;span class="c"&gt;// There is nothing special about the naming of the fields&lt;/span&gt;
    &lt;span class="c"&gt;// it is just my own convention&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;myTests&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&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;inputName&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
        &lt;span class="n"&gt;expectedOutput&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
        &lt;span class="n"&gt;expectedError&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;
    &lt;span class="p"&gt;}{&lt;/span&gt;
        &lt;span class="c"&gt;// Now we define the test scenario/struct this form we are &lt;/span&gt;
        &lt;span class="c"&gt;// using is just a shorthand of defining the struct and initialising its&lt;/span&gt;
        &lt;span class="c"&gt;// values at the same time. &lt;/span&gt;
        &lt;span class="c"&gt;// This is really just an elaborate form of:&lt;/span&gt;
        &lt;span class="c"&gt;// var myString string = "My String"&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;inputName&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Bob"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="n"&gt;expectedOutput&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Hello: Bob"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;expectedError&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="p"&gt;}&lt;/span&gt;


    &lt;span class="c"&gt;// Now that we have created our "test case" we need to actually test it&lt;/span&gt;
    &lt;span class="c"&gt;// _ is the index give by range, we don't need this&lt;/span&gt;
    &lt;span class="c"&gt;// tt is just a placeholder, it can be called anything.  I just 'tt' by convention&lt;/span&gt;
    &lt;span class="c"&gt;// because it is easy to type!&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;tt&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;myTests&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c"&gt;// First lets get our output.  I like "actual" or sometimes "got" to distinguish it from&lt;/span&gt;
        &lt;span class="c"&gt;// the "expected" output we'll compare it to&lt;/span&gt;
        &lt;span class="c"&gt;// tt.inputName is the inputName field of whatever loop of&lt;/span&gt;
        &lt;span class="c"&gt;// the testing struct we are on.  In this case "Bob"&lt;/span&gt;
        &lt;span class="n"&gt;actualOutput&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;actualError&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;MyFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;inputName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c"&gt;// Now, much like we did before lets test our outputs and make sure&lt;/span&gt;
        &lt;span class="c"&gt;// they match our expectations&lt;/span&gt;

        &lt;span class="c"&gt;// Make sure the actual error matches our expectation, which is *nil*&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;actualError&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;tt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;expectedError&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;"Should not get an 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;// Make sure our output matches&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;actualOutput&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;tt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;expectedOutput&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;"Should have gotten expected output"&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 astute reader will notice that we didn't actually &lt;em&gt;save&lt;/em&gt; any lines. In fact, it looks like we added some.  That is true for this very simple case.  The true power of this technique comes when you want to add another test.  &lt;/p&gt;

&lt;p&gt;So let's say we want to test names using Korean characters.  In our initial way of testing we'd have to copy and paste most of the function and create another, nearly duplicate, function.&lt;/p&gt;

&lt;p&gt;In our new testing format, we just add a single line. What we are adding is another value to our tesitng struct.  So right below the line for "Bob" we can add the followng:&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="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;inputName&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Jian"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;expectedOutput&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Hello: Jian"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;expectedError&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's that simple.  We added our testing "case" and since we are looping below it will loop through each struct and test them all the same.&lt;/p&gt;

&lt;p&gt;Want to add another.  Easy.  Just add another 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="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;inputName&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="n"&gt;expectedOutput&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Hello: 지안"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;expectedError&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the beginning this might all seem like overkill.  We have seen though, even with a few basic tests we gain some advantages.  To summarise you get a lot out of a little extra up front work of setting up your tests in "table" format.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Positives&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Consistency in testing&lt;/li&gt;
&lt;li&gt;Easy to add new tests&lt;/li&gt;
&lt;li&gt;Easy to add / reason about the tests&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Negatives&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Requires a little extra work up front&lt;/li&gt;
&lt;li&gt;You might need to get creative when checking output and errors since the &lt;em&gt;same&lt;/em&gt; test runs every time&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Some links on table testing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/golang/go/wiki/TableDrivenTests"&gt;https://github.com/golang/go/wiki/TableDrivenTests&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dave.cheney.net/2019/05/07/prefer-table-driven-tests"&gt;https://dave.cheney.net/2019/05/07/prefer-table-driven-tests&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dave.cheney.net/2013/06/09/writing-table-driven-tests-in-go"&gt;https://dave.cheney.net/2013/06/09/writing-table-driven-tests-in-go&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Testify
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/stretchr/testify"&gt;Testify&lt;/a&gt; is an amazing, time-saving package that I use about three functions from.  Testify is very well-designed and has high regard in the community, for good reason.  My testing purposes are generally very limited so I just don't get the &lt;em&gt;opportunity&lt;/em&gt; to use and explore all of the power that is there.&lt;/p&gt;

&lt;p&gt;There is &lt;a href="https://github.com/stretchr/testify"&gt;excellent documentation&lt;/a&gt; on their website so I'm not going to recreate it here.  I will just give you a small example of how I would use it in our example above. &lt;/p&gt;

&lt;p&gt;Do yourself a favor and spend some time reading through this package and see all of the great ways it can improve your testing.&lt;/p&gt;

&lt;p&gt;One general recommendation that might not be obvious.  99% of the time you want to use &lt;em&gt;require&lt;/em&gt; instead of &lt;em&gt;assert&lt;/em&gt;.  &lt;em&gt;Require&lt;/em&gt; will stop testing on a failure, &lt;em&gt;assert&lt;/em&gt; will continue along.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;mylib_test.go&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;package&lt;/span&gt; &lt;span class="n"&gt;mylib&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="s"&gt;"github.com/stretchr/testify/require"&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;TestMyFunction&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;var&lt;/span&gt; &lt;span class="n"&gt;myTests&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&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;inputName&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
        &lt;span class="n"&gt;expectedOutput&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
        &lt;span class="n"&gt;expectedError&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;inputName&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Bob"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="n"&gt;expectedOutput&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Hello: Bob"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;expectedError&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="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;inputName&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Jian"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;expectedOutput&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Hello: Jian"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;expectedError&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="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;inputName&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="n"&gt;expectedOutput&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Hello: 지안"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;expectedError&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="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;tt&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;myTests&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;actualOutput&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;actualError&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;MyFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;inputName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c"&gt;//if actualError != tt.expectedError {&lt;/span&gt;
        &lt;span class="c"&gt;//  t.Errorf("Should not get an error")&lt;/span&gt;
        &lt;span class="c"&gt;//}&lt;/span&gt;
        &lt;span class="n"&gt;require&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Equal&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;tt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;expectedError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;actualError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"optional message here"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c"&gt;//if actualOutput != tt.expectedOutput {&lt;/span&gt;
        &lt;span class="c"&gt;//  t.Errorf("Should have gotten expected output")&lt;/span&gt;
        &lt;span class="c"&gt;//}&lt;/span&gt;
        &lt;span class="n"&gt;require&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Equal&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;tt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;expectedOutput&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;actualOutput&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;Honestly, 90% of the time this is all I use.  In a future post we'll explore more of the massive list of assertions you get with Testify.&lt;/p&gt;

&lt;h2&gt;
  
  
  Extras
&lt;/h2&gt;

&lt;p&gt;Here are some great &lt;em&gt;extras&lt;/em&gt; on testing that I didn't have a better place for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Play around with code and share with others - &lt;a href="https://play.golang.org/"&gt;https://play.golang.org/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Some best practices for testing - &lt;a href="https://medium.com/@matryer/5-simple-tips-and-tricks-for-writing-unit-tests-in-golang-619653f90742"&gt;https://medium.com/@matryer/5-simple-tips-and-tricks-for-writing-unit-tests-in-golang-619653f90742&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Test Suites in Testify - &lt;a href="https://brunoscheufler.com/blog/2020-04-12-building-go-test-suites-using-testify"&gt;https://brunoscheufler.com/blog/2020-04-12-building-go-test-suites-using-testify&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;A really fun discussion about Testify on the &lt;em&gt;Go Time&lt;/em&gt; podcast - &lt;a href="https://changelog.com/gotime/139"&gt;https://changelog.com/gotime/139&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Thanks for reading
&lt;/h2&gt;

&lt;p&gt;If you enjoyed this or have any questions let me know.  You can contact me here &lt;a href="https://www.thehelpfulhacker.net/about/"&gt;https://www.thehelpfulhacker.net/about/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>go</category>
      <category>tdd</category>
      <category>testing</category>
    </item>
    <item>
      <title>My method of organizing email</title>
      <dc:creator>Zach Peters</dc:creator>
      <pubDate>Fri, 28 Feb 2020 00:46:03 +0000</pubDate>
      <link>https://forem.com/zpeters/my-method-of-organizing-email-1m1l</link>
      <guid>https://forem.com/zpeters/my-method-of-organizing-email-1m1l</guid>
      <description>&lt;p&gt;Today I wanted to share a quick email organization tip that I've refined over the years.  Ideally, I try to pull every piece of relevant information out of email as often as possible and stick it into Evernote or an org-mode notes file. Getting information &lt;em&gt;out&lt;/em&gt; of email and into an information system of some sort gets you 90% of the way, but there will always be that bit of info you missed in the flood of new emails.  To deal with this I follow the process below to increase my ability to find the information I need.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;The first order of business is to &lt;em&gt;get information out of email&lt;/em&gt;. Email is a great tool for communication but it was never intended to be an information repository. Search will almost always be cumbersome and even if you find the email you were looking for it can take a great deal of cognitive effort to reconstruct what the train of thought was or way that email was important.  Email generally doesn't allow for meta-data so by capturing and "editorializing" the information in your own note-taking system you can add in the relevant context&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Practice Inbox Zero.  There are really only three "states" that email should live in.  By practicing the art of quickly classifying emails in these categories you can quickly "deal with" large volumes of email rather than letting it build up:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;"New" - email that you haven't seen yet&lt;/li&gt;
&lt;li&gt;"Actions" - something you need to do&lt;/li&gt;
&lt;li&gt;"Archive" - something you need to hang on to&lt;/li&gt;
&lt;/ol&gt;


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

&lt;p&gt;Here is my modified version of "Inbox Zero" with the different folders I have found fit my work-style feel free to improve on this.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;0-Action - Emails that are requests or reminders of things i need to do.  If there is a specific task/deadline I will generally remove this to my "official" todo list in a different application and archive the email.  Generally what is in here are reminders or items I need to do &lt;em&gt;sometime.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;1-Hold - Informational emails that i need close at hand but do not represent a "todo" item.  This should be a temporary holding place for "favorites".  An example was a code that I needed for access to a system.  I knew I'd only need it for a short amount of time so I moved the email there and then moved it to 2-Archive after a week.&lt;/li&gt;
&lt;li&gt;2-Archive - This is where you put &lt;em&gt;everything&lt;/em&gt; that isn't in another folder.  Storage is cheap.  Save Everything.  Rely on good search abilities in your mail client to retrieve anything that you haven't deemed important enough to add to your notes.  If you spend more than three minutes searching for something &lt;em&gt;add it to your note-taking system&lt;/em&gt; for the future.&lt;/li&gt;
&lt;li&gt;3-Feedback - This is where I keep positive (and negative) feedback to refer back to periodically.&lt;/li&gt;
&lt;li&gt;4-Awesome - Funny emails, pick-me-ups, etc.  It's good to make time during the day to stop being so serious and enjoying work&lt;/li&gt;
&lt;li&gt;5-Templates - If i write the same email or answer the same question more than once I create a blank email and use it as a template&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;What organization systems do you use to keep the flood of email/information manageable? Please let me know!&lt;/p&gt;

</description>
      <category>email</category>
      <category>gtd</category>
      <category>organization</category>
    </item>
    <item>
      <title>Optimize Your Notetaking With Glyphs</title>
      <dc:creator>Zach Peters</dc:creator>
      <pubDate>Fri, 28 Feb 2020 00:44:36 +0000</pubDate>
      <link>https://forem.com/zpeters/optimize-your-notetaking-with-glyphs-1anc</link>
      <guid>https://forem.com/zpeters/optimize-your-notetaking-with-glyphs-1anc</guid>
      <description>&lt;p&gt;I wanted to share a quick tip that I've been using for years to make my notes (written and typed) more useful.&lt;/p&gt;

&lt;p&gt;By nature I am a pretty disorganized note-taker.  When jotting down notes I typically work in a very scattered "mind map" layout.  I find if I try to keep to any sort of outline I tend to need to squeeze more and more notes into a confined space.  What has evolved from this is basically a messy page of notes with all shorts of connecting lines, doodles, etc.&lt;/p&gt;

&lt;p&gt;While this fits my brain well it is often difficult to pick out the bits that I need to "take action" on.  Usually my understanding of what I have taken notes on is solid, but things like action items, additional research I need to do and other "meta" information gets lost in the structure - I guess you could call it "not seeing the trees for the forest"&lt;/p&gt;

&lt;p&gt;Over time I have developed a short list of standard "glyphs" that I use in my written notes to help these items stand out:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;(!)&lt;/code&gt; - Action item - Something I need to do&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;(N)&lt;/code&gt; - Note item - Something I need to document&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;(?)&lt;/code&gt;  - Research item - Something that needs further research&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;(@)&lt;/code&gt; - Contact - Someones contact information&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Do you have any note-taking tips?  I'd love to hear them.&lt;/p&gt;

</description>
      <category>lifehack</category>
      <category>notes</category>
      <category>glyphs</category>
    </item>
    <item>
      <title>Stupid Telnet Tricks</title>
      <dc:creator>Zach Peters</dc:creator>
      <pubDate>Fri, 28 Feb 2020 00:42:55 +0000</pubDate>
      <link>https://forem.com/zpeters/stupid-telnet-tricks-2p7n</link>
      <guid>https://forem.com/zpeters/stupid-telnet-tricks-2p7n</guid>
      <description>&lt;p&gt;As a system administrator, it is often necessary to do a "sanity check" from time to time.  Most problems become simple when you can break them down into their various parts.  Often, though, we take the services we use for granted.  We &lt;strong&gt;know&lt;/strong&gt; that the web server is running, email "just works"...&lt;strong&gt;right&lt;/strong&gt;???  Using some of the tricks below, you can verify that these services, in fact work, as you assumed and save yourself a lot of time and trouble.&lt;/p&gt;

&lt;h3&gt;
  
  
  HTTP
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;telnet server 80
GET / HTTP/1.1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  SMTP
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;telnet server 25
Trying X.X.X.X...
Connected to localhost.
Escape character is '^]'.
220 sever ESMTP Exim 4.69 Wed, 07 Jan 2009 21:53:57 -0600
HELO foobar.com
250 server Hello localhost [127.0.0.1]
mail from: &amp;lt;a href="mailto:test@foobar.com"&amp;gt;test@foobar.com&amp;lt;/a&amp;gt;
250 OK
rcpt to: &amp;lt;a href="mailto:you@somewhere.com"&amp;gt;you@somewhere.com&amp;lt;/a&amp;gt;
250 Accepted
data
354 Enter message, ending with "." on a line by itself
payload
.
250 OK id=1LKlz9-0000cW-Tz
quit
221 server closing connection
Connection closed by foreign host.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  POP3
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;telnet mail.foobar.com 110
Trying X.X.X.X...
Connected to mail.foobar.com.
Escape character is '^]'.
+OK The Microsoft Exchange POP3 service is ready.
USER username
+OK
PASS password
+OK User successfully logged on.
STAT
+OK 6 48274
LIST
+OK 6 48274
1 11274
2 11269
3 4929
4 4461
5 13350
6 2991
.
QUIT
+OK Microsoft Exchange Server 2007 POP3 server signing off.
Connection closed by foreign host.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What are your favorite telnet tricks?
&lt;/h2&gt;

&lt;p&gt;I am sure most of these are old-hat to many of you, what other "stupid telnet tricks" do you have?&lt;/p&gt;

</description>
      <category>telnet</category>
      <category>http</category>
      <category>troubleshooting</category>
      <category>smtp</category>
    </item>
  </channel>
</rss>
