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’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’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’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’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’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’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’s <i>close</i> to <code>reflect.DeepEqual</code> but not 100 quite). We’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’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’s just a function that returns a <code>cmp.Result</code>, so let’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’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 := &someType(a: "with", b: "value") 216 bar := &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 <= threshold && delta >= -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’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 < threshold && delta > -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’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’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’re code panics in such cases. It’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’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’s not waste more time and let’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’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’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’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’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’s already quite a bit to process. 482 </p> 483 484 <p> 485 We’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’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>