www

My personal website(s)
Log | Files | Refs

index.html (39989B)


      1 <!DOCTYPE html>
      2 
      3 <html lang="en">
      4   
      5   <head>
      6     <meta charset="utf-8">
      7     <meta http-equiv="content-type" content="text/html; charset=utf-8" />
      8 
      9     <link rel="start" href="https://vincent.demeester.fr" />
     10 
     11     <title>Vincent Demeester</title>
     12     <link rel="canonical" href="https://vincent.demeester.fr/posts/2018-08-16-gotest-tools-assertions/">
     13     <link href="https://vincent.demeester.fr/index.xml" rel="alternate" type="application/rss+xml" title="Vincent Demeester" />
     14 
     15     <link rel="openid.server" href="https://indieauth.com/openid" />
     16     <link rel="openid.delegate" href="http://vincent.demeester.fr/" />
     17     <link rel="shortcut icon" type="image/x-icon" href="favicon.ico">
     18 
     19     <link rel="stylesheet" href="/css/screen.css" type="text/css" />
     20     <link rel="stylesheet" href="/css/sbrain.css" type="text/css" />
     21     <link rel="stylesheet" href="/css/syntax.css" type="text/css" />
     22 
     23   </head>
     24   
     25   <body lang=""/>
     26   
     27 
     28 
     29 
     30 
     31 
     32 <div id="main-container">
     33   <div id="page">
     34     <article class="post">
     35       <header>
     36         <h1 class="emphnext">Golang testing — gotest.tools assertions</h1><a href='https://vincent.demeester.fr/posts/2018-08-16-gotest-tools-assertions/'></a>
     37         <address class="signature">
     38           <span class="date">Thu, 16 August, 2018</span>
     39           <span class="words">(2000 Words)</span>
     40         </address>
     41 	<ul class="tag_box inline">
     42 	  
     43 	  <li class="category"><a href="/categories/#developement">developement</a></li>
     44 	  
     45 	  
     46 	  
     47 	  
     48 	  
     49 	  <li class="tag tag-testing"><a href="/tags/#testing">testing<span>11</span></a></li>
     50 	  
     51 	  
     52 	  <li class="tag tag-golang"><a href="/tags/#golang">golang<span>12</span></a></li>
     53 	  
     54 	  
     55 	  <li class="tag tag-assert"><a href="/tags/#assert">assert<span>1</span></a></li>
     56 	  
     57 	  <br/>
     58 	  
     59 	</ul>
     60       </header>
     61       
     62       <p>Faster way to send the same command to each and every <em>pane</em> in your
     63   tmux <em>session</em>.</p>
     64 
     65 <p>Let&rsquo;s take a closer look at <a href="https://gotest.tools"><code>gotest.tools</code></a> assertions packages. This is mainly about <code>assert</code>, <code>assert/cmp</code> and
     66   <code>assert/opt</code>.</p>
     67 
     68 <blockquote>
     69 <p>Package assert provides assertions for comparing expected values to actual values. When assertion fails a helpful error
     70 message is printed.</p>
     71 </blockquote>
     72 
     73 <p>There is two main functions (<code>Assert</code> and <code>Check</code>) and some helpers (like <code>NilError</code>, …). They all take a <code>*testing.T</code> as
     74   a first argument, pretty common across testing Go libraries. Let&rsquo;s dive into those !</p>
     75 
     76       
     77       
     78 
     79 <div class="ox-hugo-toc toc">
     80 <div></div>
     81 
     82 <div class="heading">Table of Contents</div>
     83 
     84 <ul>
     85 <li><a href="#assert-and-check"><code>Assert</code> and <code>Check</code></a></li>
     86 <li><a href="#more-assert-helpers">More <code>assert</code> helpers</a></li>
     87 <li><a href="#cmp-dot-comparison"><code>cmp.Comparison</code></a>
     88 
     89 <ul>
     90 <li><a href="#equality-with-equal-and-deepequal">Equality with <code>Equal</code> and <code>DeepEqual</code></a></li>
     91 <li><a href="#errors-with-error-errorcontains-and-errortype">Errors with <code>Error</code>, <code>ErrorContains</code> and <code>ErrorType</code></a></li>
     92 <li><a href="#bonus-with-panics">Bonus with <code>Panics</code></a></li>
     93 <li><a href="#miscellaneous-with-contains-len-and-nil">Miscellaneous with <code>Contains</code>, <code>Len</code> and <code>Nil</code></a></li>
     94 <li><a href="#write-your-own-comparison">Write your own <code>Comparison</code></a></li>
     95 </ul></li>
     96 <li><a href="#conclusion">Conclusion…</a></li>
     97 </ul>
     98 
     99 <p></div>
    100 <!--endtoc--></p>
    101 
    102 <h2 id="assert-and-check"><code>Assert</code> and <code>Check</code></h2>
    103 
    104 <p>Both those functions accept a <code>Comparison</code> (we&rsquo;ll check what it is later on) and fail the test when that comparison
    105 fails. The one difference is that <code>Assert</code> will end the test execution at immediately whereas <code>Check</code> will fail the test
    106 and proceed with the rest of the test case. This is similar to <code>FailNow</code> and <code>Fail</code> from the standard library
    107 <code>testing</code>. Both have their use cases.</p>
    108 
    109 <p>We&rsquo;ll Use <code>Assert</code> for the rest of the section but any example here would work with <code>Check</code> too. When we said
    110 <code>Comparison</code> above, it&rsquo;s mainly the <a href="https://godoc.org/gotest.tools/assert#BoolOrComparison">BoolOrComparison</a> interface — it can either be a boolean expression, or a
    111 <a href="https://godoc.org/gotest.tools/assert/cmp#Comparison">cmp.Comparison</a> type. <code>Assert</code> and <code>Check</code> code will be <em>smart</em> enough to detect which one it is.</p>
    112 <div class="highlight"><pre class="chroma"><code class="language-go" data-lang="go"><span class="nx">assert</span><span class="p">.</span><span class="nf">Assert</span><span class="p">(</span><span class="nx">t</span><span class="p">,</span> <span class="nx">ok</span><span class="p">)</span>
    113 <span class="nx">assert</span><span class="p">.</span><span class="nf">Assert</span><span class="p">(</span><span class="nx">t</span><span class="p">,</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span><span class="p">)</span>
    114 <span class="nx">assert</span><span class="p">.</span><span class="nf">Assert</span><span class="p">(</span><span class="nx">t</span><span class="p">,</span> <span class="nx">foo</span><span class="p">.</span><span class="nf">IsBar</span><span class="p">())</span></code></pre></div>
    115 <p>So far not anything extra-ordinary. Let&rsquo;s first look at some more <em>helper</em> functions in the <code>assert</code> package and quickly
    116 dive a bit deeper with <code>Comparison</code>.</p>
    117 
    118 <h2 id="more-assert-helpers">More <code>assert</code> helpers</h2>
    119 
    120 <p>The additional helper functions are the following</p>
    121 
    122 <ul>
    123 <li><code>Equal</code> uses the <code>==</code> operator to assert two values are equal.</li>
    124 <li><code>DeepEqual</code> uses <code>google/go-cmp</code> to assert two values are equal (it&rsquo;s <em>close</em> to <code>reflect.DeepEqual</code> but not
    125 quite). We&rsquo;ll detail a bit more the <em>options</em> part of this function with <code>cmp.DeepEqual</code>.</li>
    126 <li><code>Error</code> fails if the error is <code>nil</code> <strong>or</strong> the error message is not the expected one.</li>
    127 <li><code>ErrorContains</code> fails if the error is <code>nil</code> <strong>or</strong> the error message does not contain the expected substring.</li>
    128 <li><code>ErrorType</code> fails if the error is <code>nil</code> <strong>or</strong> the error type is not the expected type.</li>
    129 <li><code>NilError</code> fails if the error is not <code>nil</code>.</li>
    130 </ul>
    131 
    132 <p>All those helper functions have a equivalent function in the <code>cmp</code> package that returns a <code>Comparison</code>. I, personally,
    133 prefer to use <code>assert.Check</code> or <code>assert.Assert</code> in combination with <code>cmp.Comparison</code> as it allows me to write all my
    134 assertions the same way, with built-ins comparison or with my own — i.e. <code>assert.Assert(t, is.Equal(…), &quot;message&quot;</code> or
    135 <code>assert.Assert(t, stackIsUp(c, time…), &quot;another message&quot;)</code>.</p>
    136 
    137 <h2 id="cmp-dot-comparison"><code>cmp.Comparison</code></h2>
    138 
    139 <p>This is where it get really interesting, <code>gotest.tools</code> tries to make it as easy as possible for you to create
    140 appropriate comparison — making you test readable as much as possible.</p>
    141 
    142 <p>Let&rsquo;s look a bit at the <code>cmp.Comparison</code> type.</p>
    143 <div class="highlight"><pre class="chroma"><code class="language-go" data-lang="go"><span class="kd">type</span> <span class="nx">Comparison</span> <span class="kd">func</span><span class="p">()</span> <span class="nx">Result</span></code></pre></div>
    144 <p>It&rsquo;s just a function that returns a <code>cmp.Result</code>, so let&rsquo;s look at <code>cmp.Result</code> definition.</p>
    145 <div class="highlight"><pre class="chroma"><code class="language-go" data-lang="go"><span class="kd">type</span> <span class="nx">Result</span> <span class="kd">interface</span> <span class="p">{</span>
    146 	<span class="nf">Success</span><span class="p">()</span> <span class="kt">bool</span>
    147 <span class="p">}</span></code></pre></div>
    148 <p>Result is an <code>interface</code>, thus any <em>struct</em> that provide a function <code>Success</code> that returns a <code>bool</code> can be used as a
    149 comparison result, making it really easy to use in your code. There is also existing type of result to make it even
    150 quicker to write your own comparison.</p>
    151 
    152 <ul>
    153 <li><code>ResultSuccess</code> is a constant which is returned to indicate success.</li>
    154 <li><code>ResultFailure</code> and <code>ResultFailureTemplate</code> return a failed Result with a failure message.</li>
    155 <li><code>ResultFromError</code> returns <code>ResultSuccess</code> if <code>err</code> is nil. Otherwise <code>ResultFailure</code> is returned with the error
    156 message as the failure message. It works a bit like the <code>errors.Wrap</code> function of the <a href="https://github.com/pkg/errors"><code>github.com/pkgs/errors</code></a>
    157 package.</li>
    158 </ul>
    159 
    160 <p>The <code>cmp</code> package comes with a few defined comparison that, we think, should cover a high number of use-cases. Let&rsquo;s
    161 look at them.</p>
    162 
    163 <h3 id="equality-with-equal-and-deepequal">Equality with <code>Equal</code> and <code>DeepEqual</code></h3>
    164 
    165 <blockquote>
    166 <p>Equal uses the == operator to assert two values are equal and fails the test if they are not equal.</p>
    167 
    168 <p>If the comparison fails Equal will use the variable names for x and y as part of the failure message to identify the
    169 actual and expected values.</p>
    170 
    171 <p>If either x or y are a multi-line string the failure message will include a unified diff of the two values. If the
    172 values only differ by whitespace the unified diff will be augmented by replacing whitespace characters with visible
    173 characters to identify the whitespace difference.</p>
    174 </blockquote>
    175 
    176 <p>On the other hand…</p>
    177 
    178 <blockquote>
    179 <p>DeepEqual uses google/go-cmp (<a href="http://bit.do/go-cmp">http://bit.do/go-cmp</a>) to assert two values are equal and fails the test if they are not
    180 equal.</p>
    181 
    182 <p>Package <a href="https://godoc.org/gotest.tools/assert/opt">https://godoc.org/gotest.tools/assert/opt</a> provides some additional commonly used Options.</p>
    183 </blockquote>
    184 
    185 <p>Using one or the other is as simple as : if you wrote your <code>if</code> with <code>==</code> then use <code>Equal</code>, otherwise use <code>DeepEqual</code>.
    186 <code>DeepEqual</code> (and usually <code>reflect.DeepEqual</code>) is used when you want to compare anything more complex than primitive
    187 types. One advantage of using <code>cmp.DeepEqual</code> over <code>reflect.DeepEqual</code> (in an if), is that you get a well crafted
    188 message that shows the diff between the expected and the actual structs compared – and you can pass options to it.</p>
    189 <div class="highlight"><pre class="chroma"><code class="language-go" data-lang="go"><span class="nx">assert</span><span class="p">.</span><span class="nf">Assert</span><span class="p">(</span><span class="nx">t</span><span class="p">,</span> <span class="nx">cmp</span><span class="p">.</span><span class="nf">DeepEqual</span><span class="p">([]</span><span class="kt">string</span><span class="p">{</span><span class="s">&#34;a&#34;</span><span class="p">,</span> <span class="s">&#34;b&#34;</span><span class="p">},</span> <span class="p">[]</span><span class="kt">string</span><span class="p">{</span><span class="s">&#34;b&#34;</span><span class="p">,</span> <span class="s">&#34;a&#34;</span><span class="p">}))</span>
    190 <span class="c1">// Will print something like
    191 </span><span class="c1">// --- result
    192 </span><span class="c1">// +++ exp
    193 </span><span class="c1">// {[]string}[0]:
    194 </span><span class="c1">//         -: &#34;a&#34;
    195 </span><span class="c1">//         +: &#34;b&#34;
    196 </span><span class="c1">// {[]string}[1]:
    197 </span><span class="c1">//         -: &#34;b&#34;
    198 </span><span class="c1">//         +: &#34;a&#34;
    199 </span><span class="c1"></span><span class="nx">foo</span> <span class="o">:=</span> <span class="o">&amp;</span><span class="nf">someType</span><span class="p">(</span><span class="nx">a</span><span class="p">:</span> <span class="s">&#34;with&#34;</span><span class="p">,</span> <span class="nx">b</span><span class="p">:</span> <span class="s">&#34;value&#34;</span><span class="p">)</span>
    200 <span class="nx">bar</span> <span class="o">:=</span> <span class="o">&amp;</span><span class="nf">someType</span><span class="p">(</span><span class="nx">a</span><span class="p">:</span> <span class="s">&#34;with&#34;</span><span class="p">,</span> <span class="nx">b</span><span class="p">:</span> <span class="s">&#34;value&#34;</span><span class="p">)</span>
    201 <span class="c1">// the following will succeed as foo and bar are _DeepEqual_
    202 </span><span class="c1"></span><span class="nx">assert</span><span class="p">.</span><span class="nf">Assert</span><span class="p">(</span><span class="nx">t</span><span class="p">,</span> <span class="nx">cmp</span><span class="p">.</span><span class="nf">DeepEqual</span><span class="p">(</span><span class="nx">foo</span><span class="p">,</span> <span class="nx">bar</span><span class="p">))</span></code></pre></div>
    203 <p>When using <code>DeepEqual</code>, you may end up with really weird behavior(s). You may want to ignore some fields, or consider
    204 <code>nil</code> slice or map the same as empty ones ; or more common, your <em>struct</em> contains some unexported fields that you
    205 cannot use when comparing (as they are not exported 😓). In those case, you can use <code>go-cmp</code> options.</p>
    206 
    207 <p>Some existing one are :</p>
    208 
    209 <ul>
    210 <li><a href="https://godoc.org/github.com/google/go-cmp/cmp/cmpopts#EquateEmpty"><code>EquateEmpty</code></a> returns a Comparer option that determines all maps and slices with a length of zero to be equal,
    211 regardless of whether they are nil.</li>
    212 <li><a href="https://godoc.org/github.com/google/go-cmp/cmp/cmpopts#IgnoreFields"><code>IgnoreFields</code></a> returns an Option that ignores exported fields of the given names on a single struct type. The struct
    213 type is specified by passing in a value of that type.</li>
    214 <li><a href="https://godoc.org/github.com/google/go-cmp/cmp/cmpopts#IgnoreUnexported"><code>IgnoreUnexported</code></a> returns an Option that only ignores the immediate unexported fields of a struct, including anonymous
    215 fields of unexported types.</li>
    216 <li><a href="https://godoc.org/github.com/google/go-cmp/cmp/cmpopts#SortSlices"><code>SortSlices</code></a> returns a Transformer option that sorts all <code>[]V</code></li>
    217 <li>… and <a href="https://godoc.org/github.com/google/go-cmp/cmp/cmpopts">more</a> 👼</li>
    218 </ul>
    219 
    220 <p><code>gotest.tools</code> also defines some <strong>and</strong> you can define yours ! As an example, <code>gotest.tools</code> defines <code>TimeWithThreshold</code>
    221 and <code>DurationWithThreshold</code> that allows to not fails if the time (or duration) is not exactly the same but in the
    222 specified threshold we specified. Here is the code for <code>DurationWithThreshold</code> for inspiration.</p>
    223 <div class="highlight"><pre class="chroma"><code class="language-go" data-lang="go"><span class="c1">// DurationWithThreshold returns a gocmp.Comparer for comparing time.Duration. The
    224 </span><span class="c1">// Comparer returns true if the difference between the two Duration values is
    225 </span><span class="c1">// within the threshold and neither value is zero.
    226 </span><span class="c1"></span><span class="kd">func</span> <span class="nf">DurationWithThreshold</span><span class="p">(</span><span class="nx">threshold</span> <span class="nx">time</span><span class="p">.</span><span class="nx">Duration</span><span class="p">)</span> <span class="nx">gocmp</span><span class="p">.</span><span class="nx">Option</span> <span class="p">{</span>
    227 	<span class="k">return</span> <span class="nx">gocmp</span><span class="p">.</span><span class="nf">Comparer</span><span class="p">(</span><span class="nf">cmpDuration</span><span class="p">(</span><span class="nx">threshold</span><span class="p">))</span>
    228 <span class="p">}</span>
    229 
    230 <span class="kd">func</span> <span class="nf">cmpDuration</span><span class="p">(</span><span class="nx">threshold</span> <span class="nx">time</span><span class="p">.</span><span class="nx">Duration</span><span class="p">)</span> <span class="kd">func</span><span class="p">(</span><span class="nx">x</span><span class="p">,</span> <span class="nx">y</span> <span class="nx">time</span><span class="p">.</span><span class="nx">Duration</span><span class="p">)</span> <span class="kt">bool</span> <span class="p">{</span>
    231 	<span class="k">return</span> <span class="kd">func</span><span class="p">(</span><span class="nx">x</span><span class="p">,</span> <span class="nx">y</span> <span class="nx">time</span><span class="p">.</span><span class="nx">Duration</span><span class="p">)</span> <span class="kt">bool</span> <span class="p">{</span>
    232 		<span class="k">if</span> <span class="nx">x</span> <span class="o">==</span> <span class="mi">0</span> <span class="o">||</span> <span class="nx">y</span> <span class="o">==</span> <span class="mi">0</span> <span class="p">{</span>
    233 			<span class="k">return</span> <span class="kc">false</span>
    234 		<span class="p">}</span>
    235 		<span class="nx">delta</span> <span class="o">:=</span> <span class="nx">x</span> <span class="o">-</span> <span class="nx">y</span>
    236 		<span class="k">return</span> <span class="nx">delta</span> <span class="o">&lt;=</span> <span class="nx">threshold</span> <span class="o">&amp;&amp;</span> <span class="nx">delta</span> <span class="o">&gt;=</span> <span class="o">-</span><span class="nx">threshold</span>
    237 	<span class="p">}</span>
    238 <span class="p">}</span></code></pre></div>
    239 <p>Another good example for those options is when you want to skip some field. In <a href="https://github.com/docker/docker"><code>docker/docker</code></a> we want to be able to
    240 easily check for equality between two service specs, but those might have different <code>CreatedAt</code> and <code>UpdatedAt</code> values
    241 that we usually don&rsquo;t care about – what we want is to make sure it happens in the past 20 seconds. You can easily define
    242 an option for that.</p>
    243 <div class="highlight"><pre class="chroma"><code class="language-go" data-lang="go"><span class="kd">func</span> <span class="nf">cmpServiceOpts</span><span class="p">()</span> <span class="nx">cmp</span><span class="p">.</span><span class="nx">Option</span> <span class="p">{</span>
    244 	<span class="kd">const</span> <span class="nx">threshold</span> <span class="p">=</span> <span class="mi">20</span> <span class="o">*</span> <span class="nx">time</span><span class="p">.</span><span class="nx">Second</span>
    245 
    246 	<span class="c1">// Apply withinThreshold only for the following fields
    247 </span><span class="c1"></span>	<span class="nx">metaTimeFields</span> <span class="o">:=</span> <span class="kd">func</span><span class="p">(</span><span class="nx">path</span> <span class="nx">cmp</span><span class="p">.</span><span class="nx">Path</span><span class="p">)</span><span class="kt">bool</span> <span class="p">{</span>
    248 		<span class="k">switch</span> <span class="nx">path</span><span class="p">.</span><span class="nf">String</span><span class="p">()</span> <span class="p">{</span>
    249 		<span class="k">case</span> <span class="s">&#34;Meta.CreatedAt&#34;</span><span class="p">,</span> <span class="s">&#34;Meta.UpdatedAt&#34;</span><span class="p">:</span>
    250 			<span class="k">return</span> <span class="kc">true</span>
    251 		<span class="p">}</span>
    252 		<span class="k">return</span> <span class="kc">false</span>
    253 	<span class="p">}</span>
    254 	<span class="c1">// have a 20s threshold for the time value that will be passed
    255 </span><span class="c1"></span>	<span class="nx">withinThreshold</span> <span class="o">:=</span> <span class="nx">cmp</span><span class="p">.</span><span class="nf">Comparer</span><span class="p">(</span><span class="kd">func</span><span class="p">(</span><span class="nx">x</span><span class="p">,</span> <span class="nx">y</span> <span class="nx">time</span><span class="p">.</span><span class="nx">Time</span><span class="p">)</span> <span class="kt">bool</span> <span class="p">{</span>
    256 		<span class="nx">delta</span> <span class="o">:=</span> <span class="nx">x</span><span class="p">.</span><span class="nf">Sub</span><span class="p">(</span><span class="nx">y</span><span class="p">)</span>
    257 		<span class="k">return</span> <span class="nx">delta</span> <span class="p">&lt;</span> <span class="nx">threshold</span> <span class="o">&amp;&amp;</span> <span class="nx">delta</span> <span class="p">&gt;</span> <span class="o">-</span><span class="nx">threshold</span>
    258 	<span class="p">})</span>
    259 
    260 	<span class="k">return</span> <span class="nx">cmp</span><span class="p">.</span><span class="nf">FilterPath</span><span class="p">(</span><span class="nx">metaTimeFields</span><span class="p">,</span> <span class="nx">withinThreshold</span><span class="p">)</span>
    261 <span class="p">}</span></code></pre></div>
    262 <p>I recommend you look at the <a href="https://godoc.org/gotest.tools/assert/opt">gotest.tools/assert/opt</a> documentation to see which one are defined and how to use them.</p>
    263 
    264 <h3 id="errors-with-error-errorcontains-and-errortype">Errors with <code>Error</code>, <code>ErrorContains</code> and <code>ErrorType</code></h3>
    265 
    266 <p>Checking for errors is <strong>very common</strong> in Go, having <code>Comparison</code> function for it was a requirement.</p>
    267 
    268 <ul>
    269 <li><code>Error</code> fails if the error is <code>nil</code> <strong>or</strong> the error message is not the expected one.</li>
    270 <li><code>ErrorContains</code> fails if the error is <code>nil</code> <strong>or</strong> the error message does not contain the expected substring.</li>
    271 <li><code>ErrorType</code> fails if the error is <code>nil</code> <strong>or</strong> the error type is not the expected type.</li>
    272 </ul>
    273 
    274 <p>Let&rsquo;s first look at the most used : <code>Error</code> and <code>ErrorContains</code>.</p>
    275 <div class="highlight"><pre class="chroma"><code class="language-go" data-lang="go"><span class="kd">var</span> <span class="nx">err</span> <span class="kt">error</span>
    276 <span class="c1">// will fail with : expected an error, got nil
    277 </span><span class="c1"></span><span class="nx">assert</span><span class="p">.</span><span class="nf">Check</span><span class="p">(</span><span class="nx">t</span><span class="p">,</span> <span class="nx">cmp</span><span class="p">.</span><span class="nf">Error</span><span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="s">&#34;message in a bottle&#34;</span><span class="p">))</span>
    278 <span class="nx">err</span> <span class="p">=</span> <span class="nx">errors</span><span class="p">.</span><span class="nf">Wrap</span><span class="p">(</span><span class="nx">errors</span><span class="p">.</span><span class="nf">New</span><span class="p">(</span><span class="s">&#34;other&#34;</span><span class="p">),</span> <span class="s">&#34;wrapped&#34;</span><span class="p">)</span>
    279 <span class="c1">// will fail with : expected error &#34;other&#34;, got &#34;wrapped: other&#34;
    280 </span><span class="c1"></span><span class="nx">assert</span><span class="p">.</span><span class="nf">Check</span><span class="p">(</span><span class="nx">t</span><span class="p">,</span> <span class="nx">cmp</span><span class="p">.</span><span class="nf">Error</span><span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="s">&#34;other&#34;</span><span class="p">))</span>
    281 <span class="c1">// will succeed
    282 </span><span class="c1"></span><span class="nx">assert</span><span class="p">.</span><span class="nf">Check</span><span class="p">(</span><span class="nx">t</span><span class="p">,</span> <span class="nx">cmp</span><span class="p">.</span><span class="nf">ErrorContains</span><span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="s">&#34;other&#34;</span><span class="p">))</span></code></pre></div>
    283 <p>As you can see <code>ErrorContains</code> is especially useful when working with <em>wrapped</em> errors.
    284 Now let&rsquo;s look at <code>ErrorType</code>.</p>
    285 <div class="highlight"><pre class="chroma"><code class="language-go" data-lang="go"><span class="kd">var</span> <span class="nx">err</span> <span class="kt">error</span>
    286 <span class="c1">// will fail with : error is nil, not StubError
    287 </span><span class="c1"></span><span class="nx">assert</span><span class="p">.</span><span class="nf">Check</span><span class="p">(</span><span class="nx">t</span><span class="p">,</span> <span class="nx">cmp</span><span class="p">.</span><span class="nf">ErrorType</span><span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="nx">StubError</span><span class="p">{}))</span>
    288 
    289 <span class="nx">err</span> <span class="o">:=</span> <span class="nx">StubError</span><span class="p">{</span><span class="s">&#34;foo&#34;</span><span class="p">}</span>
    290 <span class="c1">// will succeed
    291 </span><span class="c1"></span><span class="nx">assert</span><span class="p">.</span><span class="nf">Check</span><span class="p">(</span><span class="nx">t</span><span class="p">,</span> <span class="nx">cmp</span><span class="p">.</span><span class="nf">ErrorType</span><span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="nx">StubError</span><span class="p">{}))</span>
    292 
    293 <span class="c1">// Note that it also work with a function returning an error
    294 </span><span class="c1"></span><span class="kd">func</span> <span class="nf">foo</span><span class="p">()</span> <span class="kt">error</span> <span class="p">{}</span>
    295 <span class="nx">assert</span><span class="p">.</span><span class="nf">Check</span><span class="p">(</span><span class="nx">t</span><span class="p">,</span> <span class="nx">cmp</span><span class="p">.</span><span class="nf">ErrorType</span><span class="p">(</span><span class="nx">foo</span><span class="p">,</span> <span class="nx">StubError</span><span class="p">{}))</span></code></pre></div>
    296 <h3 id="bonus-with-panics">Bonus with <code>Panics</code></h3>
    297 
    298 <p>Sometimes, a code is supposed to <em>panic</em>, see <a href="https://golang.org/doc/effective%5Fgo.html#panic">Effective Go (#Panic)</a> for more information. And thus, you may want to make
    299 sure you&rsquo;re code panics in such cases. It&rsquo;s always a bit tricky to test a code that panic as you have to use a deferred
    300 function to recover the panic — but then if the panic doesn&rsquo;t happen how do you fail the test ?</p>
    301 
    302 <p>This is where <code>Panics</code> comes handy.</p>
    303 <div class="highlight"><pre class="chroma"><code class="language-go" data-lang="go"><span class="kd">func</span> <span class="nf">foo</span><span class="p">(</span><span class="nx">shouldPanic</span> <span class="kt">bool</span><span class="p">)</span> <span class="p">{</span>
    304 	<span class="k">if</span> <span class="nx">shouldPanic</span> <span class="p">{</span>
    305 		<span class="nb">panic</span><span class="p">(</span><span class="s">&#34;booooooooooh&#34;</span><span class="p">)</span>
    306 	<span class="p">}</span>
    307 	<span class="c1">// don&#39;t worry, be happy
    308 </span><span class="c1"></span><span class="p">}</span>
    309 <span class="c1">// will fail with : did not panic
    310 </span><span class="c1"></span><span class="nx">assert</span><span class="p">.</span><span class="nf">Check</span><span class="p">(</span><span class="nx">t</span><span class="p">,</span> <span class="nx">cmp</span><span class="p">.</span><span class="nf">Panics</span><span class="p">(</span><span class="nf">foo</span><span class="p">(</span><span class="kc">false</span><span class="p">)))</span>
    311 <span class="c1">// will succeed
    312 </span><span class="c1"></span><span class="nx">assert</span><span class="p">.</span><span class="nf">Check</span><span class="p">(</span><span class="nx">t</span><span class="p">,</span> <span class="nx">cmp</span><span class="p">.</span><span class="nf">Panics</span><span class="p">(</span><span class="nf">foo</span><span class="p">(</span><span class="kc">true</span><span class="p">)))</span></code></pre></div>
    313 <h3 id="miscellaneous-with-contains-len-and-nil">Miscellaneous with <code>Contains</code>, <code>Len</code> and <code>Nil</code></h3>
    314 
    315 <p>Those last three <em>built-in</em> <code>Comparison</code> are pretty straightforward.</p>
    316 
    317 <ul>
    318 <li><p><code>Contains</code> succeeds if item is in collection. Collection may be a string, map, slice, or array.</p>
    319 
    320 <p>If collection is a string, item must also be a string, and is compared using <code>strings.Contains()</code>. If collection is a
    321 Map, contains will succeed if item is a key in the map. If collection is a slice or array, item is compared to each
    322 item in the sequence using <code>=reflect.DeepEqual()=</code>.</p></li>
    323 
    324 <li><p><code>Len</code> succeeds if the sequence has the expected length.</p></li>
    325 
    326 <li><p><code>Nil</code> succeeds if obj is a nil interface, pointer, or function.</p></li>
    327 </ul>
    328 <div class="highlight"><pre class="chroma"><code class="language-go" data-lang="go"><span class="c1">// Contains works on string, map, slice or arrays
    329 </span><span class="c1"></span><span class="nx">assert</span><span class="p">.</span><span class="nf">Check</span><span class="p">(</span><span class="nx">t</span><span class="p">,</span> <span class="nx">cmp</span><span class="p">.</span><span class="nf">Contains</span><span class="p">(</span><span class="s">&#34;foobar&#34;</span><span class="p">,</span> <span class="s">&#34;foo&#34;</span><span class="p">))</span>
    330 <span class="nx">assert</span><span class="p">.</span><span class="nf">Check</span><span class="p">(</span><span class="nx">t</span><span class="p">,</span> <span class="nx">cmp</span><span class="p">.</span><span class="nf">Contains</span><span class="p">([]</span><span class="kt">string</span><span class="p">{</span><span class="s">&#34;a&#34;</span><span class="p">,</span> <span class="s">&#34;b&#34;</span><span class="p">,</span> <span class="s">&#34;c&#34;</span><span class="p">},</span> <span class="s">&#34;b&#34;</span><span class="p">))</span>
    331 <span class="nx">assert</span><span class="p">.</span><span class="nf">Check</span><span class="p">(</span><span class="nx">t</span><span class="p">,</span> <span class="nx">cmp</span><span class="p">.</span><span class="nf">Contains</span><span class="p">(</span><span class="kd">map</span><span class="p">[</span><span class="kt">string</span><span class="p">]</span><span class="kt">int</span><span class="p">{</span><span class="s">&#34;a&#34;</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="s">&#34;b&#34;</span><span class="p">:</span> <span class="mi">2</span><span class="p">,</span> <span class="s">&#34;c&#34;</span><span class="p">:</span> <span class="mi">4</span><span class="p">},</span> <span class="s">&#34;b&#34;</span><span class="p">))</span>
    332 
    333 <span class="c1">// Len also works on string, map, slice or arrays
    334 </span><span class="c1"></span><span class="nx">assert</span><span class="p">.</span><span class="nf">Check</span><span class="p">(</span><span class="nx">t</span><span class="p">,</span> <span class="nx">cmp</span><span class="p">.</span><span class="nf">Len</span><span class="p">(</span><span class="s">&#34;foobar&#34;</span><span class="p">,</span> <span class="mi">6</span><span class="p">))</span>
    335 <span class="nx">assert</span><span class="p">.</span><span class="nf">Check</span><span class="p">(</span><span class="nx">t</span><span class="p">,</span> <span class="nx">cmp</span><span class="p">.</span><span class="nf">Len</span><span class="p">([]</span><span class="kt">string</span><span class="p">{</span><span class="s">&#34;a&#34;</span><span class="p">,</span> <span class="s">&#34;b&#34;</span><span class="p">,</span> <span class="s">&#34;c&#34;</span><span class="p">},</span> <span class="mi">3</span><span class="p">))</span>
    336 <span class="nx">assert</span><span class="p">.</span><span class="nf">Check</span><span class="p">(</span><span class="nx">t</span><span class="p">,</span> <span class="nx">cmp</span><span class="p">.</span><span class="nf">Len</span><span class="p">(</span><span class="kd">map</span><span class="p">[</span><span class="kt">string</span><span class="p">]</span><span class="kt">int</span><span class="p">{</span><span class="s">&#34;a&#34;</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="s">&#34;b&#34;</span><span class="p">:</span> <span class="mi">2</span><span class="p">,</span> <span class="s">&#34;c&#34;</span><span class="p">:</span> <span class="mi">4</span><span class="p">},</span> <span class="mi">3</span><span class="p">))</span>
    337 
    338 <span class="c1">// Nil
    339 </span><span class="c1"></span><span class="kd">var</span> <span class="nx">foo</span> <span class="o">*</span><span class="nx">MyStruc</span>
    340 <span class="nx">assert</span><span class="p">.</span><span class="nf">Check</span><span class="p">(</span><span class="nx">t</span><span class="p">,</span> <span class="nx">cmp</span><span class="p">.</span><span class="nf">Nil</span><span class="p">(</span><span class="nx">foo</span><span class="p">))</span>
    341 <span class="nx">assert</span><span class="p">.</span><span class="nf">Check</span><span class="p">(</span><span class="nx">t</span><span class="p">,</span> <span class="nx">cmp</span><span class="p">.</span><span class="nf">Nil</span><span class="p">(</span><span class="nf">bar</span><span class="p">()))</span></code></pre></div>
    342 <p>But let&rsquo;s not waste more time and let&rsquo;s see how to write our own <code>Comparison</code> !</p>
    343 
    344 <h3 id="write-your-own-comparison">Write your own <code>Comparison</code></h3>
    345 
    346 <p>One of the main aspect of <code>gotest.tools/assert</code> is to make it easy for developer to write as less boilerplate code as
    347 possible while writing tests. Writing your own <code>Comparison</code> allows you to write a well named function that will be easy
    348 to read and that can be re-used across your tests.</p>
    349 
    350 <p>Let&rsquo;s look back at the <code>cmp.Comparison</code> and <code>cmp.Result</code> types.</p>
    351 <div class="highlight"><pre class="chroma"><code class="language-go" data-lang="go"><span class="kd">type</span> <span class="nx">Comparison</span> <span class="kd">func</span><span class="p">()</span> <span class="nx">Result</span>
    352 
    353 <span class="kd">type</span> <span class="nx">Result</span> <span class="kd">interface</span> <span class="p">{</span>
    354 	<span class="nf">Success</span><span class="p">()</span> <span class="kt">bool</span>
    355 <span class="p">}</span></code></pre></div>
    356 <p>A <code>Comparison</code> for <code>assert.Check</code> or <code>assert.Check</code> is a function that return a <code>Result</code>, it&rsquo;s pretty straightforward to
    357 implement, especially with <code>cmp.ResultSuccess</code> and <code>cmp.ResultFailure(…)</code> (as seen previously).</p>
    358 <div class="highlight"><pre class="chroma"><code class="language-go" data-lang="go"><span class="kd">func</span> <span class="nf">regexPattern</span><span class="p">(</span><span class="nx">value</span> <span class="kt">string</span><span class="p">,</span> <span class="nx">pattern</span> <span class="kt">string</span><span class="p">)</span> <span class="nx">cmp</span><span class="p">.</span><span class="nx">Comparison</span> <span class="p">{</span>
    359 	<span class="k">return</span> <span class="kd">func</span><span class="p">()</span> <span class="nx">cmp</span><span class="p">.</span><span class="nx">Result</span> <span class="p">{</span>
    360 		<span class="nx">re</span> <span class="o">:=</span> <span class="nx">regexp</span><span class="p">.</span><span class="nf">MustCompile</span><span class="p">(</span><span class="nx">pattern</span><span class="p">)</span>
    361 		<span class="k">if</span> <span class="nx">re</span><span class="p">.</span><span class="nf">MatchString</span><span class="p">(</span><span class="nx">value</span><span class="p">)</span> <span class="p">{</span>
    362 			<span class="k">return</span> <span class="nx">cmp</span><span class="p">.</span><span class="nx">ResultSuccess</span>
    363 		<span class="p">}</span>
    364 		<span class="k">return</span> <span class="nx">cmp</span><span class="p">.</span><span class="nf">ResultFailure</span><span class="p">(</span>
    365 			<span class="nx">fmt</span><span class="p">.</span><span class="nf">Sprintf</span><span class="p">(</span><span class="s">&#34;%q did not match pattern %q&#34;</span><span class="p">,</span> <span class="nx">value</span><span class="p">,</span> <span class="nx">pattern</span><span class="p">))</span>
    366 	<span class="p">}</span>
    367 <span class="p">}</span>
    368 
    369 <span class="c1">// To use it
    370 </span><span class="c1"></span><span class="nx">assert</span><span class="p">.</span><span class="nf">Check</span><span class="p">(</span><span class="nx">t</span><span class="p">,</span> <span class="nf">regexPattern</span><span class="p">(</span><span class="s">&#34;12345.34&#34;</span><span class="p">,</span> <span class="s">`\d+.\d\d`</span><span class="p">))</span></code></pre></div>
    371 <p>As you can see, it&rsquo;s pretty easy to implement, and you can do quite a lot in there easily. If a function call returns an
    372 error inside of your <code>Comparison</code> function, you can use <code>cmp.ResultFromError</code> for example. Having something like
    373 <code>assert.Check(t, isMyServerUp(&quot;:8080&quot;))</code> is way more readable than a 30-line of code to check it.</p>
    374 
    375 <h2 id="conclusion">Conclusion…</h2>
    376 
    377 <p>… and that&rsquo;s a wrap. We only looked at the <code>assert</code> package of <a href="https://gotest.tools"><code>gotest.tools</code></a> so far, but it&rsquo;s already quite a bit to process.</p>
    378 
    379 <p>We&rsquo;ve seen :</p>
    380 
    381 <ul>
    382 <li>the main functions provided by this package : <code>assert.Assert</code> and <code>assert.Check</code></li>
    383 <li>some helper functions like <code>assert.NilError</code>, …</li>
    384 <li>the <code>assert/cmp</code>, and <code>assert/opt</code> sub-package that allows you to write more custom <code>Comparison</code></li>
    385 </ul>
    386 
    387 <p>Next time, we&rsquo;ll look at the <code>skip</code> package, that is a really simple wrapper on top of <code>testing.Skip</code> function.</p>
    388 
    389       
    390     </article>
    391     <hr />
    392     <div class="prev-next">
    393       
    394       <a class="paging-link prev" href="/posts/2018-09-01-gotest-tools-skip/" title="Golang testing — gotest.tools skip">← Previous post</a>
    395       
    396 
    397       
    398       <a class="paging-link next" href="/posts/2018-07-28-gotest-tools-intro/" title="Golang testing — gotest.tools introduction">Next post →</a>
    399       
    400     </div>
    401 
    402   </div>
    403 </div>
    404 
    405 <footer>
    406   <nav>
    407     
    408     <a href="/">home</a>
    409     <span class="text-muted"> | </span>
    410     
    411     <a href="/about">about</a>
    412     <span class="text-muted"> | </span>
    413     
    414     <a href="/archive">archive</a>
    415     <span class="text-muted"> | </span>
    416     
    417     <a href="/categories">categories</a>
    418     <span class="text-muted"> | </span>
    419     
    420     <a href="/tags">tags</a>
    421     <span class="text-muted"> | </span>
    422     
    423     <a href="https://twitter.com/vdemeest">twitter</a>
    424     <span class="text-muted"> | </span>
    425     
    426     <a href="https://github.com/vdemeester">github</a>
    427     <span class="text-muted"> | </span>
    428     
    429     <a href="https://vincent.demeester.fr/index.xml">rss</a>
    430   </nav>
    431   <br/>
    432   <address>
    433     <span class="copyright">
    434       Content and design by Vincent Demeester
    435       (<a rel="licence" href="http://creativecommons.org/licenses/by-nc-sa/3.0/">Some rights reserved</a>)
    436     </span><br />
    437     <span class="engine">
    438       Powered by <a href="https://gohugo.io/">Hugo</a> and <a href="https://github.com/kaushalmodi/ox-hugo/">ox-hugo</a>
    439     </span>
    440   </address>
    441 </footer>
    442 </body>
    443