www

My personal website(s)
Log | Files | Refs

2018-08-16-gotest-tools-assertions.html (23155B)


      1 <!DOCTYPE html>
      2 <html lang="en">
      3 <head>
      4 <!-- Sep 03, 2024 -->
      5 <meta charset="utf-8" />
      6 <meta name="viewport" content="width=device-width, initial-scale=1" />
      7 <title>Golang testing — gotest.tools assertions</title>
      8 <meta name="author" content="Vincent Demeester" />
      9 <meta name="generator" content="Org Mode" />
     10 <link rel='icon' type='image/x-icon' href='/images/favicon.ico'/>
     11 <meta name='viewport' content='width=device-width, initial-scale=1'>
     12 <link rel='stylesheet' href='/css/new.css' type='text/css'/>
     13 <link rel='stylesheet' href='/css/syntax.css' type='text/css'/>
     14 <link href='/index.xml' rel='alternate' type='application/rss+xml' title='Vincent Demeester' />
     15 </head>
     16 <body>
     17 <main id="content" class="content">
     18 <header>
     19 <h1 class="title">Golang testing — gotest.tools assertions</h1>
     20 </header><nav id="table-of-contents" role="doc-toc">
     21 <h2>Table of Contents</h2>
     22 <div id="text-table-of-contents" role="doc-toc">
     23 <ul>
     24 <li><a href="#Introduction">Introduction</a></li>
     25 <li><a href="#%3DAssert%3D%20and%20%3DCheck%3D"><code>Assert</code> and <code>Check</code></a></li>
     26 <li><a href="#More%20%3Dassert%3D%20helpers">More <code>assert</code> helpers</a></li>
     27 <li><a href="#%3Dcmp.Comparison%3D"><code>cmp.Comparison</code></a>
     28 <ul>
     29 <li><a href="#Equality%20with%20%3DEqual%3D%20and%20%3DDeepEqual%3D">Equality with <code>Equal</code> and <code>DeepEqual</code></a></li>
     30 <li><a href="#Errors%20with%20%3DError%3D%2C%20%3DErrorContains%3D%20and%20%3DErrorType%3D">Errors with <code>Error</code>, <code>ErrorContains</code> and <code>ErrorType</code></a></li>
     31 <li><a href="#Bonus%20with%20%3DPanics%3D">Bonus with <code>Panics</code></a></li>
     32 <li><a href="#Miscellaneous%20with%20%3DContains%3D%2C%20%3DLen%3D%20and%20%3DNil%3D">Miscellaneous with <code>Contains</code>, <code>Len</code> and <code>Nil</code></a></li>
     33 <li><a href="#Write%20your%20own%20%3DComparison%3D">Write your own <code>Comparison</code></a></li>
     34 </ul>
     35 </li>
     36 <li><a href="#Conclusion%E2%80%A6">Conclusion…</a></li>
     37 </ul>
     38 </div>
     39 </nav>
     40 <section id="outline-container-Introduction" class="outline-2">
     41 <h2 id="Introduction">Introduction</h2>
     42 <div class="outline-text-2" id="text-Introduction">
     43 <p>
     44 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
     45 <code>assert/opt</code>.
     46 </p>
     47 
     48 <blockquote>
     49 <p>
     50 Package assert provides assertions for comparing expected values to actual values. When assertion fails a helpful error
     51 message is printed.
     52 </p>
     53 </blockquote>
     54 
     55 <p>
     56 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
     57 a first argument, pretty common across testing Go libraries. Let&rsquo;s dive into those !
     58 </p>
     59 </div>
     60 </section>
     61 <section id="outline-container-%3DAssert%3D%20and%20%3DCheck%3D" class="outline-2">
     62 <h2 id="%3DAssert%3D%20and%20%3DCheck%3D"><code>Assert</code> and <code>Check</code></h2>
     63 <div class="outline-text-2" id="text-%3DAssert%3D%20and%20%3DCheck%3D">
     64 <p>
     65 Both those functions accept a <code>Comparison</code> (we&rsquo;ll check what it is later on) and fail the test when that comparison
     66 fails. The one difference is that <code>Assert</code> will end the test execution at immediately whereas <code>Check</code> will fail the test
     67 and proceed with the rest of the test case. This is similar to <code>FailNow</code> and <code>Fail</code> from the standard library
     68 <code>testing</code>. Both have their use cases.
     69 </p>
     70 
     71 <p>
     72 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
     73 <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
     74 <a href="https://godoc.org/gotest.tools/assert/cmp#Comparison">cmp.Comparison</a> type. <code>Assert</code> and <code>Check</code> code will be <i>smart</i> enough to detect which one it is.
     75 </p>
     76 
     77 <div class="org-src-container">
     78 <pre class="src src-go">assert.Assert(t, ok)
     79 assert.Assert(t, err != nil)
     80 assert.Assert(t, foo.IsBar())
     81 </pre>
     82 </div>
     83 
     84 <p>
     85 So far not anything extra-ordinary. Let&rsquo;s first look at some more <i>helper</i> functions in the <code>assert</code> package and quickly
     86 dive a bit deeper with <code>Comparison</code>.
     87 </p>
     88 </div>
     89 </section>
     90 <section id="outline-container-More%20%3Dassert%3D%20helpers" class="outline-2">
     91 <h2 id="More%20%3Dassert%3D%20helpers">More <code>assert</code> helpers</h2>
     92 <div class="outline-text-2" id="text-More%20%3Dassert%3D%20helpers">
     93 <p>
     94 The additional helper functions are the following
     95 </p>
     96 
     97 <ul class="org-ul">
     98 <li><code>Equal</code> uses the <code>==</code> operator to assert two values are equal.</li>
     99 <li><code>DeepEqual</code> uses <code>google/go-cmp</code> to assert two values are equal (it&rsquo;s <i>close</i> to <code>reflect.DeepEqual</code> but not
    100 quite). We&rsquo;ll detail a bit more the <i>options</i> part of this function with <code>cmp.DeepEqual</code>.</li>
    101 <li><code>Error</code> fails if the error is <code>nil</code> <b>or</b> the error message is not the expected one.</li>
    102 <li><code>ErrorContains</code> fails if the error is <code>nil</code> <b>or</b> the error message does not contain the expected substring.</li>
    103 <li><code>ErrorType</code> fails if the error is <code>nil</code> <b>or</b> the error type is not the expected type.</li>
    104 <li><code>NilError</code> fails if the error is not <code>nil</code>.</li>
    105 </ul>
    106 
    107 <p>
    108 All those helper functions have a equivalent function in the <code>cmp</code> package that returns a <code>Comparison</code>. I, personally,
    109 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
    110 assertions the same way, with built-ins comparison or with my own — i.e. <code>assert.Assert(t, is.Equal(…), "message"</code> or
    111 <code>assert.Assert(t, stackIsUp(c, time…), "another message")</code>.
    112 </p>
    113 </div>
    114 </section>
    115 <section id="outline-container-%3Dcmp.Comparison%3D" class="outline-2">
    116 <h2 id="%3Dcmp.Comparison%3D"><code>cmp.Comparison</code></h2>
    117 <div class="outline-text-2" id="text-%3Dcmp.Comparison%3D">
    118 <p>
    119 This is where it get really interesting, <code>gotest.tools</code> tries to make it as easy as possible for you to create
    120 appropriate comparison — making you test readable as much as possible.
    121 </p>
    122 
    123 <p>
    124 Let&rsquo;s look a bit at the <code>cmp.Comparison</code> type.
    125 </p>
    126 
    127 <div class="org-src-container">
    128 <pre class="src src-go">type Comparison func() Result
    129 </pre>
    130 </div>
    131 
    132 <p>
    133 It&rsquo;s just a function that returns a <code>cmp.Result</code>, so let&rsquo;s look at <code>cmp.Result</code> definition.
    134 </p>
    135 
    136 <div class="org-src-container">
    137 <pre class="src src-go">type Result interface {
    138         Success() bool
    139 }
    140 </pre>
    141 </div>
    142 
    143 <p>
    144 Result is an <code>interface</code>, thus any <i>struct</i> that provide a function <code>Success</code> that returns a <code>bool</code> can be used as a
    145 comparison result, making it really easy to use in your code. There is also existing type of result to make it even
    146 quicker to write your own comparison.
    147 </p>
    148 
    149 <ul class="org-ul">
    150 <li><code>ResultSuccess</code> is a constant which is returned to indicate success.</li>
    151 <li><code>ResultFailure</code> and <code>ResultFailureTemplate</code> return a failed Result with a failure message.</li>
    152 <li><code>ResultFromError</code> returns <code>ResultSuccess</code> if <code>err</code> is nil. Otherwise <code>ResultFailure</code> is returned with the error
    153 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>
    154 package.</li>
    155 </ul>
    156 
    157 <p>
    158 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
    159 look at them.
    160 </p>
    161 </div>
    162 <div id="outline-container-Equality%20with%20%3DEqual%3D%20and%20%3DDeepEqual%3D" class="outline-3">
    163 <h3 id="Equality%20with%20%3DEqual%3D%20and%20%3DDeepEqual%3D">Equality with <code>Equal</code> and <code>DeepEqual</code></h3>
    164 <div class="outline-text-3" id="text-Equality%20with%20%3DEqual%3D%20and%20%3DDeepEqual%3D">
    165 <blockquote>
    166 <p>
    167 Equal uses the == operator to assert two values are equal and fails the test if they are not equal.
    168 </p>
    169 
    170 <p>
    171 If the comparison fails Equal will use the variable names for x and y as part of the failure message to identify the
    172 actual and expected values.
    173 </p>
    174 
    175 <p>
    176 If either x or y are a multi-line string the failure message will include a unified diff of the two values. If the
    177 values only differ by whitespace the unified diff will be augmented by replacing whitespace characters with visible
    178 characters to identify the whitespace difference.
    179 </p>
    180 </blockquote>
    181 
    182 <p>
    183 On the other hand…
    184 </p>
    185 
    186 <blockquote>
    187 <p>
    188 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
    189 equal.
    190 </p>
    191 
    192 <p>
    193 Package <a href="https://godoc.org/gotest.tools/assert/opt">https://godoc.org/gotest.tools/assert/opt</a> provides some additional commonly used Options.
    194 </p>
    195 </blockquote>
    196 
    197 <p>
    198 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>.
    199 <code>DeepEqual</code> (and usually <code>reflect.DeepEqual</code>) is used when you want to compare anything more complex than primitive
    200 types. One advantage of using <code>cmp.DeepEqual</code> over <code>reflect.DeepEqual</code> (in an if), is that you get a well crafted
    201 message that shows the diff between the expected and the actual structs compared – and you can pass options to it.
    202 </p>
    203 
    204 <div class="org-src-container">
    205 <pre class="src src-go">assert.Assert(t, cmp.DeepEqual([]string{"a", "b"}, []string{"b", "a"}))
    206 // Will print something like
    207 // --- result
    208 // +++ exp
    209 // {[]string}[0]:
    210 //         -: "a"
    211 //         +: "b"
    212 // {[]string}[1]:
    213 //         -: "b"
    214 //         +: "a"
    215 foo := &amp;someType(a: "with", b: "value")
    216 bar := &amp;someType(a: "with", b: "value")
    217 // the following will succeed as foo and bar are _DeepEqual_
    218 assert.Assert(t, cmp.DeepEqual(foo, bar))
    219 </pre>
    220 </div>
    221 
    222 <p>
    223 When using <code>DeepEqual</code>, you may end up with really weird behavior(s). You may want to ignore some fields, or consider
    224 <code>nil</code> slice or map the same as empty ones ; or more common, your <i>struct</i> contains some unexported fields that you
    225 cannot use when comparing (as they are not exported 😓). In those case, you can use <code>go-cmp</code> options.
    226 </p>
    227 
    228 <p>
    229 Some existing one are :
    230 </p>
    231 <ul class="org-ul">
    232 <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,
    233 regardless of whether they are nil.</li>
    234 <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
    235 type is specified by passing in a value of that type.</li>
    236 <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
    237 fields of unexported types.</li>
    238 <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>
    239 <li>… and <a href="https://godoc.org/github.com/google/go-cmp/cmp/cmpopts">more</a> 👼</li>
    240 </ul>
    241 
    242 <p>
    243 <code>gotest.tools</code> also defines some <b>and</b> you can define yours ! As an example, <code>gotest.tools</code> defines <code>TimeWithThreshold</code>
    244 and <code>DurationWithThreshold</code> that allows to not fails if the time (or duration) is not exactly the same but in the
    245 specified threshold we specified. Here is the code for <code>DurationWithThreshold</code> for inspiration.
    246 </p>
    247 
    248 <div class="org-src-container">
    249 <pre class="src src-go">// DurationWithThreshold returns a gocmp.Comparer for comparing time.Duration. The
    250 // Comparer returns true if the difference between the two Duration values is
    251 // within the threshold and neither value is zero.
    252 func DurationWithThreshold(threshold time.Duration) gocmp.Option {
    253         return gocmp.Comparer(cmpDuration(threshold))
    254 }
    255 
    256 func cmpDuration(threshold time.Duration) func(x, y time.Duration) bool {
    257         return func(x, y time.Duration) bool {
    258                 if x == 0 || y == 0 {
    259                         return false
    260                 }
    261                 delta := x - y
    262                 return delta &lt;= threshold &amp;&amp; delta &gt;= -threshold
    263         }
    264 }
    265 </pre>
    266 </div>
    267 
    268 <p>
    269 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
    270 easily check for equality between two service specs, but those might have different <code>CreatedAt</code> and <code>UpdatedAt</code> values
    271 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
    272 an option for that.
    273 </p>
    274 
    275 <div class="org-src-container">
    276 <pre class="src src-go">func cmpServiceOpts() cmp.Option {
    277         const threshold = 20 * time.Second
    278 
    279         // Apply withinThreshold only for the following fields
    280         metaTimeFields := func(path cmp.Path)bool {
    281                 switch path.String() {
    282                 case "Meta.CreatedAt", "Meta.UpdatedAt":
    283                         return true
    284                 }
    285                 return false
    286         }
    287         // have a 20s threshold for the time value that will be passed
    288         withinThreshold := cmp.Comparer(func(x, y time.Time) bool {
    289                 delta := x.Sub(y)
    290                 return delta &lt; threshold &amp;&amp; delta &gt; -threshold
    291         })
    292 
    293         return cmp.FilterPath(metaTimeFields, withinThreshold)
    294 }
    295 </pre>
    296 </div>
    297 
    298 <p>
    299 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.
    300 </p>
    301 </div>
    302 </div>
    303 <div id="outline-container-Errors%20with%20%3DError%3D%2C%20%3DErrorContains%3D%20and%20%3DErrorType%3D" class="outline-3">
    304 <h3 id="Errors%20with%20%3DError%3D%2C%20%3DErrorContains%3D%20and%20%3DErrorType%3D">Errors with <code>Error</code>, <code>ErrorContains</code> and <code>ErrorType</code></h3>
    305 <div class="outline-text-3" id="text-Errors%20with%20%3DError%3D%2C%20%3DErrorContains%3D%20and%20%3DErrorType%3D">
    306 <p>
    307 Checking for errors is <b>very common</b> in Go, having <code>Comparison</code> function for it was a requirement.
    308 </p>
    309 
    310 <ul class="org-ul">
    311 <li><code>Error</code> fails if the error is <code>nil</code> <b>or</b> the error message is not the expected one.</li>
    312 <li><code>ErrorContains</code> fails if the error is <code>nil</code> <b>or</b> the error message does not contain the expected substring.</li>
    313 <li><code>ErrorType</code> fails if the error is <code>nil</code> <b>or</b> the error type is not the expected type.</li>
    314 </ul>
    315 
    316 <p>
    317 Let&rsquo;s first look at the most used : <code>Error</code> and <code>ErrorContains</code>.
    318 </p>
    319 
    320 <div class="org-src-container">
    321 <pre class="src src-go">var err error
    322 // will fail with : expected an error, got nil
    323 assert.Check(t, cmp.Error(err, "message in a bottle"))
    324 err = errors.Wrap(errors.New("other"), "wrapped")
    325 // will fail with : expected error "other", got "wrapped: other"
    326 assert.Check(t, cmp.Error(err, "other"))
    327 // will succeed
    328 assert.Check(t, cmp.ErrorContains(err, "other"))
    329 </pre>
    330 </div>
    331 
    332 <p>
    333 As you can see <code>ErrorContains</code> is especially useful when working with <i>wrapped</i> errors.
    334 Now let&rsquo;s look at <code>ErrorType</code>.
    335 </p>
    336 
    337 <div class="org-src-container">
    338 <pre class="src src-go">var err error
    339 // will fail with : error is nil, not StubError
    340 assert.Check(t, cmp.ErrorType(err, StubError{}))
    341 
    342 err := StubError{"foo"}
    343 // will succeed
    344 assert.Check(t, cmp.ErrorType(err, StubError{}))
    345 
    346 // Note that it also work with a function returning an error
    347 func foo() error {}
    348 assert.Check(t, cmp.ErrorType(foo, StubError{}))
    349 </pre>
    350 </div>
    351 </div>
    352 </div>
    353 <div id="outline-container-Bonus%20with%20%3DPanics%3D" class="outline-3">
    354 <h3 id="Bonus%20with%20%3DPanics%3D">Bonus with <code>Panics</code></h3>
    355 <div class="outline-text-3" id="text-Bonus%20with%20%3DPanics%3D">
    356 <p>
    357 Sometimes, a code is supposed to <i>panic</i>, see <a href="https://golang.org/doc/effective_go.html#panic">Effective Go (#Panic)</a> for more information. And thus, you may want to make
    358 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
    359 function to recover the panic — but then if the panic doesn&rsquo;t happen how do you fail the test ?
    360 </p>
    361 
    362 <p>
    363 This is where <code>Panics</code> comes handy.
    364 </p>
    365 
    366 <div class="org-src-container">
    367 <pre class="src src-go">func foo(shouldPanic bool) {
    368         if shouldPanic {
    369                 panic("booooooooooh")
    370         }
    371         // don't worry, be happy
    372 }
    373 // will fail with : did not panic
    374 assert.Check(t, cmp.Panics(foo(false)))
    375 // will succeed
    376 assert.Check(t, cmp.Panics(foo(true)))
    377 </pre>
    378 </div>
    379 </div>
    380 </div>
    381 <div id="outline-container-Miscellaneous%20with%20%3DContains%3D%2C%20%3DLen%3D%20and%20%3DNil%3D" class="outline-3">
    382 <h3 id="Miscellaneous%20with%20%3DContains%3D%2C%20%3DLen%3D%20and%20%3DNil%3D">Miscellaneous with <code>Contains</code>, <code>Len</code> and <code>Nil</code></h3>
    383 <div class="outline-text-3" id="text-Miscellaneous%20with%20%3DContains%3D%2C%20%3DLen%3D%20and%20%3DNil%3D">
    384 <p>
    385 Those last three <i>built-in</i> <code>Comparison</code> are pretty straightforward.
    386 </p>
    387 
    388 <ul class="org-ul">
    389 <li><p>
    390 <code>Contains</code> succeeds if item is in collection. Collection may be a string, map, slice, or array.
    391 </p>
    392 
    393 <p>
    394 If collection is a string, item must also be a string, and is compared using <code>strings.Contains()</code>. If collection is a
    395 Map, contains will succeed if item is a key in the map. If collection is a slice or array, item is compared to each
    396 item in the sequence using <code>=reflect.DeepEqual()=</code>.
    397 </p></li>
    398 <li><code>Len</code> succeeds if the sequence has the expected length.</li>
    399 <li><code>Nil</code> succeeds if obj is a nil interface, pointer, or function.</li>
    400 </ul>
    401 
    402 <div class="org-src-container">
    403 <pre class="src src-go">// Contains works on string, map, slice or arrays
    404 assert.Check(t, cmp.Contains("foobar", "foo"))
    405 assert.Check(t, cmp.Contains([]string{"a", "b", "c"}, "b"))
    406 assert.Check(t, cmp.Contains(map[string]int{"a": 1, "b": 2, "c": 4}, "b"))
    407 
    408 // Len also works on string, map, slice or arrays
    409 assert.Check(t, cmp.Len("foobar", 6))
    410 assert.Check(t, cmp.Len([]string{"a", "b", "c"}, 3))
    411 assert.Check(t, cmp.Len(map[string]int{"a": 1, "b": 2, "c": 4}, 3))
    412 
    413 // Nil
    414 var foo *MyStruc
    415 assert.Check(t, cmp.Nil(foo))
    416 assert.Check(t, cmp.Nil(bar()))
    417 </pre>
    418 </div>
    419 
    420 <p>
    421 But let&rsquo;s not waste more time and let&rsquo;s see how to write our own <code>Comparison</code> !
    422 </p>
    423 </div>
    424 </div>
    425 <div id="outline-container-Write%20your%20own%20%3DComparison%3D" class="outline-3">
    426 <h3 id="Write%20your%20own%20%3DComparison%3D">Write your own <code>Comparison</code></h3>
    427 <div class="outline-text-3" id="text-Write%20your%20own%20%3DComparison%3D">
    428 <p>
    429 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
    430 possible while writing tests. Writing your own <code>Comparison</code> allows you to write a well named function that will be easy
    431 to read and that can be re-used across your tests.
    432 </p>
    433 
    434 <p>
    435 Let&rsquo;s look back at the <code>cmp.Comparison</code> and <code>cmp.Result</code> types.
    436 </p>
    437 
    438 <div class="org-src-container">
    439 <pre class="src src-go">type Comparison func() Result
    440 
    441 type Result interface {
    442         Success() bool
    443 }
    444 </pre>
    445 </div>
    446 
    447 <p>
    448 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
    449 implement, especially with <code>cmp.ResultSuccess</code> and <code>cmp.ResultFailure(…)</code> (as seen previously).
    450 </p>
    451 
    452 <div class="org-src-container">
    453 <pre class="src src-go">func regexPattern(value string, pattern string) cmp.Comparison {
    454         return func() cmp.Result {
    455                 re := regexp.MustCompile(pattern)
    456                 if re.MatchString(value) {
    457                         return cmp.ResultSuccess
    458                 }
    459                 return cmp.ResultFailure(
    460                         fmt.Sprintf("%q did not match pattern %q", value, pattern))
    461         }
    462 }
    463 
    464 // To use it
    465 assert.Check(t, regexPattern("12345.34", `\d+.\d\d`))
    466 </pre>
    467 </div>
    468 
    469 <p>
    470 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
    471 error inside of your <code>Comparison</code> function, you can use <code>cmp.ResultFromError</code> for example. Having something like
    472 <code>assert.Check(t, isMyServerUp(":8080"))</code> is way more readable than a 30-line of code to check it.
    473 </p>
    474 </div>
    475 </div>
    476 </section>
    477 <section id="outline-container-Conclusion%E2%80%A6" class="outline-2">
    478 <h2 id="Conclusion%E2%80%A6">Conclusion…</h2>
    479 <div class="outline-text-2" id="text-Conclusion%E2%80%A6">
    480 <p>
    481 … 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.
    482 </p>
    483 
    484 <p>
    485 We&rsquo;ve seen :
    486 </p>
    487 <ul class="org-ul">
    488 <li>the main functions provided by this package : <code>assert.Assert</code> and <code>assert.Check</code></li>
    489 <li>some helper functions like <code>assert.NilError</code>, …</li>
    490 <li>the <code>assert/cmp</code>, and <code>assert/opt</code> sub-package that allows you to write more custom <code>Comparison</code></li>
    491 </ul>
    492 
    493 <p>
    494 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.
    495 </p>
    496 
    497 <p>
    498 **
    499 </p>
    500 </div>
    501 </section>
    502 </main>
    503 <footer id="postamble" class="status">
    504 <footer>
    505      <small><a href="/" rel="history">Index</a> • <a href="/sitemap.html">Sitemap</a> • <a href="https://dl.sbr.pm/">Files</a></small><br/>
    506      <small class='questions'>Questions, comments ? Please use my <a href="https://lists.sr.ht/~vdemeester/public-inbox">public inbox</a> by sending a plain-text email to <a href="mailto:~vdemeester/public-inbox@lists.sr.ht">~vdemeester/public-inbox@lists.sr.ht</a>.</small><br/>
    507      <small class='copyright'>
    508       Content and design by Vincent Demeester
    509       (<a rel='licence' href='http://creativecommons.org/licenses/by-nc-sa/3.0/'>Some rights reserved</a>)
    510     </small><br />
    511 </footer>
    512 </footer>
    513 </body>
    514 </html>