-
Notifications
You must be signed in to change notification settings - Fork 1
/
05-advanced.slide
911 lines (636 loc) · 26.3 KB
/
05-advanced.slide
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
# Generics, Packages & Testing
Course Go
Tags: golang, go
## Outline
- Generics
- Packages
- Testing
## Generics
## Why generics?
- Generic algorithms and functions
- Sorting
- Comparing
- Maps, filters, etc.
- True abstract data types
- Lists
- Trees
- Priority queues, etc.
- Reusability
- Safety
[Go Blog: Why Generics?](https://go.dev/blog/why-generics)
## Life without generics
- You either:
- Have to define the same function for every type you would like to use
- Use `inferface{}` and type switch the concrete type at runtime
## Non-generic functions
- Good old "normal" functions as used for decades
.play assets/lecture-05/generics/normal-print.go /START OMIT/,/END OMIT/
## Function overloading
- Not supported in Go
- Avoids [name mangling](https://en.wikipedia.org/wiki/Name_mangling)
.play assets/lecture-05/generics/overloaded-prints.go /START OMIT/,/END OMIT/
## Multiple implementations
- An implemenetation for each type
.play assets/lecture-05/generics/multiple-prints.go /START OMIT/,/END OMIT/
## Runtime "generics"
- Has runtime overhead
- Tidious to implement
- Usually combined with a type switch
.play assets/lecture-05/generics/runtime-print.go /START OMIT/,/END OMIT/
## Generic function
- Generics introduced in [Go version 1.18](https://tip.golang.org/doc/go1.18)
- Adds type parameters to functions and structures
- Usually named `T`, `U`, `V`, ... but words can be used as well
- The type parameters have to be instantiated on use
.play assets/lecture-05/generics/print-instantiated.go /START OMIT/,/END OMIT/
## Selection of generic function
- The instance of the type parameter can sometimes be omitted
- Inferred by the compiler
.play assets/lecture-05/generics/print.go /START OMIT/,/END OMIT/
## Compilation type checks
- Compiler checks that the instantiated type and arguments match
.play assets/lecture-05/generics/print-check.go /START OMIT/,/END OMIT/
## Comparable with multiple implementations
.play assets/lecture-05/generics/orderable-multiple.go /START OMIT/,/END OMIT/
## Type sets: orderable
- Used to constrain the type parameter
- The type parameter then supports intersection of operations of given types
.play assets/lecture-05/generics/type-set-orderable.go /START OMIT/,/END OMIT/
## Type sets: unorderable
.play assets/lecture-05/generics/type-set-unorderable.go /START OMIT/,/END OMIT/
## Type sets: hierarchy
.code assets/lecture-05/generics/type-set-hierarchy.go /START OMIT/,/END OMIT/
## Compile time or runtime?
- `interface{}`/`any`
- Runtime
- Type parameters
- Compile time
```
$ go tool compile -S file.go > file.s
```
or
```
$ go build -gcflags=main=-S
```
## Assembly: concrete implementation
.code assets/lecture-05/generics/orderable-single.go /START OMIT/,/END OMIT/
Compiles into:
```
"".compare STEXT nosplit size=7 args=0x10 locals=0x0 funcid=0x0 align=0x0
0x0000 00000 (generics/orderable-single.go:7) TEXT "".compare(SB), NOSPLIT|ABIInternal, $0-16
0x0000 00000 (generics/orderable-single.go:7) PCDATA $3, $1
0x0000 00000 (generics/orderable-single.go:8) CMPQ BX, AX
0x0003 00003 (generics/orderable-single.go:8) SETGT AL
0x0006 00006 (generics/orderable-single.go:8) RET
```
## Assembly: generic implementation (1/2)
.code assets/lecture-05/generics/type-set-orderable.go /START OMIT/,/END OMIT/
Compiles into:
## Assembly: generic implementation (2/2)
```
"".compare[go.shape.int_0] STEXT dupok nosplit size=7 args=0x18 locals=0x0 funcid=0x0 align=0x0
0x0000 00000 (generics/type-set-orderable.go:11) TEXT "".compare[go.shape.int_0](SB), DUPOK|NOSPLIT|ABIInternal, $0-24
0x0000 00000 (generics/type-set-orderable.go:11) PCDATA $3, $1
0x0000 00000 (generics/type-set-orderable.go:12) CMPQ CX, BX
0x0003 00003 (generics/type-set-orderable.go:12) SETGT AL
0x0006 00006 (generics/type-set-orderable.go:12) RET
"".compare[go.shape.float64_0] STEXT dupok nosplit size=8 args=0x18 locals=0x0 funcid=0x0 align=0x0
0x0000 00000 (generics/type-set-orderable.go:11) TEXT "".compare[go.shape.float64_0](SB), DUPOK|NOSPLIT|ABIInternal, $0-24
0x0000 00000 (generics/type-set-orderable.go:11) PCDATA $3, $1
0x0000 00000 (generics/type-set-orderable.go:12) UCOMISD X0, X1
0x0004 00004 (generics/type-set-orderable.go:12) SETHI AL
0x0007 00007 (generics/type-set-orderable.go:12) RET
"".compare[go.shape.string_0] STEXT dupok size=120 args=0x28 locals=0x28 funcid=0x0 align=0x0
0x0000 00000 (generics/type-set-orderable.go:11) TEXT "".compare[go.shape.string_0](SB), DUPOK|ABIInternal, $40-40
0x0000 00000 (generics/type-set-orderable.go:11) CMPQ SP, 16(R14)
0x0004 00004 (generics/type-set-orderable.go:11) PCDATA $0, $-2
0x0004 00004 (generics/type-set-orderable.go:11) JLS 63
...
...
0x002a 00042 (generics/type-set-orderable.go:12) PCDATA $1, $1
0x002a 00042 (generics/type-set-orderable.go:12) CALL runtime.cmpstring(SB)
...
...
0x003e 00062 (generics/type-set-orderable.go:12) RET
```
## No automatic type conversion
- Reminder: Go does not coerce types
.play assets/lecture-05/generics/no-conversions.go
## Type approximations
- Types can be approximated using the `~` operator
- `~int` includes:
- The `int` type and
- All other types that have `int` as their underlying type
.play assets/lecture-05/generics/type-approximations.go /START OMIT/,/END OMIT/
## Generic method vs. generic function
.play assets/lecture-05/generics/slice.go /START OMIT/,/END OMIT/
## Map utilities (1/2)
.play assets/lecture-05/generics/utilities-maps.go /START OMIT/,/MIDDLE OMIT/
## Map utilities (2/2)
.play assets/lecture-05/generics/utilities-maps.go /MIDDLE OMIT/,/END OMIT/
## Slice utilities (1/2)
.play assets/lecture-05/generics/utilities-slices.go /START OMIT/,/MIDDLE OMIT/
## Slice utilities (2/2)
.play assets/lecture-05/generics/utilities-slices.go /MIDDLE OMIT/,/END OMIT/
## Packages
## cmp
- As ordered types are often used it was defined in the **`cmp.Ordered`** interface
- I.e. the interface contains all built-in types that support **`<`**, **`>`**, **`<=`**, **`>=`** operations
- Do not confuse it with **`comparable`** interface built-in to the language
- Encapsulates types that can compared on equality using **`==`** and **`!=`** operator
- Also contains generic functions for comparing values:
- `Cmp`
- `Less`
- `Or`
[Go Packages: cmp](https://pkg.go.dev/cmp)
## slices
- Generic slice manipulating functions
- `Insert`, `Delete`
- `Contains`, `Index`
- `Sort`, `IsSorted`, `BinarySearch`
- `Min`, `Max`
- `Clone`, `Compare`, `Equal`
- `Grow`, `Clip`
- *And a few more...*
- Most exist in the "`Func`" variant that is used to alter the default behavior
[Go Packages: slices](https://pkg.go.dev/slices)
## slices
.play assets/lecture-05/packages/slices.go /START OMIT/,/END OMIT/
## maps
- A few generic map manipulating functions
- `DeleteFunc`
- `Clone`, `Copy`
- `Equal`, `EqualFunc`
- *Thats it...*
[Go Packages: maps](https://pkg.go.dev/maps)
## math
- Maximum and minimum values for integer types
- Math constants
- E, Pi, Phi
- Common math functions
- Trigonometric functions
- Powers, logarithms
- Floor, ceil
- *And many more...*
- Almost all functions are defined for `float64`
[Go Packages: math](https://pkg.go.dev/math)
## strings
- String manipulating functions
- `Cut`, `Trim`, `Split`, `Join`
- `Contains`, `Index`
- `ToLower`, `ToUpper`, `ToTitle`
- *And many more...*
- String builder
- Use whenever dynamically building strings
- String reader
[Go Packages: strings](https://pkg.go.dev/strings)
## bytes
- Pretty much the same as with `strings` package
[Go Packages: bytes](https://pkg.go.dev/bytes)
## strconv
- Conversion functions
- `Atoi`, `Itoa`
- `FormatInt`, `ParseInt`
- `FormatFloat`, `ParseFloat`
- `FormatBool`, `ParseBool`
- `Quote`, `Unquote`
- *And a few more related functions...*
[Go Packages: strconv](https://pkg.go.dev/strconv)
## path/filepath
- Package for operation filesystem paths
- Platform independent
- Utility functions
- `Abs`, `Rel`
- `Base`, `Dir`, `Ext`
- `Join`, `Split`
- `Clean`
- `WalkDir`
[Go Packages: path/filepath](https://pkg.go.dev/path/filepath)
## io
- Mainly defines I/O interfaces
- `Reader`, `Writer`, `Seeker`, `Closer`
- And some of their combinations
- Also implements a few functions
- `Copy`, `ReadAll`, ...
.play assets/lecture-05/packages/io.go /START OMIT/,/END OMIT/
[Go Packages: io](https://pkg.go.dev/io)
## io/fs
- Extends basic I/O interfaces with filesystem interfaces
- `FS`, `StatFS`, `SubFS`
- `File`, `FileMode`, `FileInfo`
[Go Packages: io](https://pkg.go.dev/io/fs)
## bufio
- Implements buffered I/O which leverage the `io` package interfaces
- Three main types
- `Reader`
- `Writer`
- `Scanner`
[Go Packages: bufio](https://pkg.go.dev/bufio)
## bufio
.play assets/lecture-05/packages/bufio.go /START OMIT/,/END OMIT/
## os
- Platform independant interface to OS functionalities
- File management
- `File`, `FileInfo` types
- `Chmod`, `Chown`
- `Create`, `New`, `Open`, `Mkdir`, `Rename`, `Remove`
- Process management
- `Process`, `ProcessState` types
- `Kill`, `Signal`, `Exit`
- Environment
- `Environ`, `Getenv`, `Setenv`
[Go Packages: os](https://pkg.go.dev/os)
## os
.play assets/lecture-05/packages/os.go /START OMIT/,/END OMIT/
## log
- Simple logging package
- Introduces new type
- `Logger`
- Logging functions
- `Print`, `Fatal`, `Panic`
- `Printf`, `Fatalf`, `Panicf`
- `Println`, `Fatalln`, `Panicln`
- Logging format can be specified using flags
- `Ldate`, `Ltime`, `LUTC`, `Lmsgprefix`, ...
[Go Packages: log](https://pkg.go.dev/log)
## log/slog
- More feature rich
- New `Logger` type
- `Handler`s
- `TextHandler` and `JSONHandler` are built-in
- Custom handlers can be also defined
- Provides structured logging
- Levels: Debug, Info, Warn, Error
- Groups
- Contexts
- Atributtes
[Go Packages: log/slog](https://pkg.go.dev/log/slog)
## log/slog
.play assets/lecture-05/packages/slog.go /START OMIT/,/END OMIT/
## crypto
- Encryption: [aes](https://pkg.go.dev/crypto/aes), [rsa](https://pkg.go.dev/crypto/rsa), [ed25519](https://pkg.go.dev/crypto/ed25519)
- Hashing: [md5](https://pkg.go.dev/crypto/md5), [sha256](https://pkg.go.dev/crypto/sha256), [sha512](https://pkg.go.dev/crypto/sha512)
- [hmac](https://pkg.go.dev/crypto/hmac), [rand](https://pkg.go.dev/crypto/rand), [tls](https://pkg.go.dev/crypto/tls), [x509](https://pkg.go.dev/crypto/x509)
[Go Packages: crypto](https://pkg.go.dev/crypto)
- Encryption: [chacha20](https://pkg.go.dev/golang.org/x/crypto/chacha20)
- Hashing: [argon2](https://pkg.go.dev/golang.org/x/crypto/argon2), [bcrypt](https://pkg.go.dev/golang.org/x/crypto/bcrypt), [pbkdf2](https://pkg.go.dev/golang.org/x/crypto/pbkdf2)
- Certificates: [acme](https://pkg.go.dev/golang.org/x/crypto/acme), [pkcs12](https://pkg.go.dev/golang.org/x/crypto/pkcs12)
- [ssh](https://pkg.go.dev/golang.org/x/crypto/ssh)
[Go Packages: x/crypto](https://pkg.go.dev/golang.org/x/crypto)
- And many more...
## Testing
## Golang Testing Frameworks
- Many testing frameworks
- Unit testing
- BDD testing
- Expect-like frameworks and libraries
- REST API testing
- Performance analysis
[Awesome Go: Testing](https://go.libhunt.com/categories/559-testing)
## Pyramid, Ice-cream and Diamond
.image assets/lecture-05/testing/pyramids.svg 400 _
## Standard library
## Standard testing framework
- Standard `testing` package is pretty powerful
- Sufficient for most of testing scenarios
- Also includes benchmarking and fuzzing
- More on that later/in the next lecture
- Most third party libraries and frameworks build on top the standard library
[Go Packages: testing](https://pkg.go.dev/testing)
## Standard testing framework
- The framework looks for source files with the **`_test.go`** suffix
- Each test is a function in these files that has to:
- Start with the **`Test`** prefix
- Take in a single argument of type **`*testing.T`**
## The T type
- Throughout the test you interact with the **`*testing.T`** argument
- It exports bunch of methods for evaluating the test
- **`Log`**: prints additional information
- Only if the test fails or if verbose mode is enabled
- **`Fail`**: marks the test as failed and continues execution
- **`FailNow`**: marks the test as failed and exits
- **`SkipNow`**: completely skips the test execution
- **`Skip`**: equivalent to calling **`Log`** and **`SkipNow`**
- **`Error`**: equivalent to calling **`Log`** and **`Fail`**
- **`Fatal`**: equivalent to calling **`Log`** and **`FailNow`**
## The T type
- The methods which print information also exist in the "formatted" form
- **`Logf`**
- **`Skipf`**
- **`Errorf`**
- **`Fatalf`**
## The T type
- **`Cleanup`**: registers a function that gets called when the test completes
- Like `defer`
- **`TempDir`**: returns a temporary directory for the test to use
- After the test is completed, it is aumatically removed
- **`Helper`**: marks function as helper function
- When printing file and line information, it is skipped
- Makes test outputs cleaner
- **`Run`**: runs a subtest in separate goroutine
- **`Parallel`**: enables test to be run in parallel
- And a few more...
[Go Packages: testing T type](https://pkg.go.dev/testing#T)
## Unit tests
- Stored in `X_test.go` files
- Where X is the name name of the file tested
- The files share the same directory
```
models/
├── user.go
├── user_test.go
├── product.go
└── product_test.go
```
- The same usually goes for the packages
- This is the only case when multiple packages in a single directory are allowed
```
models/
├── user.go // package models
├── user_test.go // package models_test
├── product.go // package models
└── product_test.go // package models_test
```
## Separate test package
- You could also stuff all tests and source code to the same package
```
models/
├── user.go // package models
├── user_test.go // package models
├── product.go // package models
└── product_test.go // package models
```
- But separating them is generally the preffered way
- Makes the tests more focused on the exported API
- Tests do not depend on implementation details
- However, you may want to test unexported parts of your program
- Can it be done then?
## Unit tests
- You can export some unexported part of code for testing
- Can be done with a neat trick
- Create **`export_test.go`** file in the original source code package
- As the file is part of the original non-test package
- It can reference unexported types
- As the file has **`_test.go`** suffix
- It is included in the testing phase
- Exluded from source code
.code assets/lecture-05/testing/export_test.go
## Running tests
- The testing toolkit is part of the **`go`** executable
- In the form of **`go test`** command
- To run all tests recursivelly: **`go` `test` `./...`**
- You can also specify a package or a single file
- Same as with running **`go build`**/**`go run`** etc.
- You can also specify part of the test suite by matching the test's names
- **`go test -run $REGEX ./...`**
- The REGEX can be as simple as "Users" which runs all tests which contain the word "Users" in their names
## Add example: separate package, exported
.code assets/lecture-05/testing/exported-add-separated-package.go
.code assets/lecture-05/testing/exported-add-separated-package_test.go
## Add example: separate package, unexported (1/2)
.code assets/lecture-05/testing/unexported-add-separated-package.go
.code assets/lecture-05/testing/unexported-add-separated-package_test.go
## Add example: separate package, unexported (2/2)
- Works if we export it via **`export_test.go`** file like so:
.code assets/lecture-05/testing/add-export_test.go
## Test failures: Error
.code assets/lecture-05/testing/add-error.go
.code assets/lecture-05/testing/add-error_test.go /START OMIT/,/END OMIT/
## Test failures: Log, Skip, Fatal
.code assets/lecture-05/testing/add-fatal_test.go /START OMIT/,/END OMIT/
## Table-driven tests
.code assets/lecture-05/testing/add-table-driven_test.go /START OMIT/,/END OMIT/
## Running tests in parallel
- By default:
- Tests in different packages are run in parallel
- Tests that share package are run sequentially
- Go uses the number of available CPUs
- Can be changed with the **`-p`** option when calling **`go test`**
- However, tests in the same package can be run in parallel
- Signalled by calling the **`t.Parallel()`** method
- Sequential tests are run first, one by one
- Parallel tests are run after all sequantial tests are done, all at once
[Mercari Engineering: Test parallelization in Go by Yoshiki Shibata](https://engineering.mercari.com/en/blog/entry/20220408-how_to_use_t_parallel)
## Running tests in parallel
.code assets/lecture-05/testing/add-parallel_test.go /START OMIT/,/END OMIT/
## Notes on test names
- Although test names like `TestUserInvalid` are generally fine
- They are ambiguous
- Is the operation in test invalid or is the user invalid?
- If so, what operation or in what state is the user?
- In the end, the programmer will have to study the test itself...
- It is often suggested to follow more verbose naming conventions
- [One such example](https://osherove.com/blog/2005/4/3/naming-standards-for-unit-tests.html) by [Roy Oshorove](https://osherove.com)
- "UnitOfWork_StateUnderTest_ExpectedBehavior"
- `TestCreateUser_MissingNameInBody_ReturnsBadRequest`
[Medium: Naming tests in Golang by Diogo Mateus](https://medium.com/getground/naming-tests-in-golang-c58c188bb9a1)
## Tips & tricks
- You can use build tags and/or short mode
- To learn more about build tags run: **`go help buildconstraint`**
- Short tests can be run with: **`go test -short ./...`** and checked via the T
.code assets/lecture-05/testing/add-short_test.go /START OMIT/,/END OMIT/
- Auxilery data are stored in `testdata` directories
- Ignored by the compiler
```
testdata/
├── input.txt
└── output-golden.txt
processor.go
processor_test.go
```
## Code coverage
- The testing toolkit can display code coverage
- **`go test -cover ./...`**
```
ok github.com/course-go/lectures/package 0.167s coverage: 85.0% of statements
```
- Or generate cover profile
- **`go test -coverprofile $PROFILE_NAME ./...`**
```
mode: set
test/internal/numbers/numbers.go:3.24,5.2 1 1
test/internal/numbers/numbers.go:7.29,9.2 1 0
```
## Inspecting code coverage
- The profile can also be inspected using the go tool
- Preview coverage for each function:
- **`go tool cover -func $PROFILE_NAME`**
```
test/internal/numbers/numbers.go:3: add 100.0%
test/internal/numbers/numbers.go:7: subtract 0.0%
total: (statements) 50.0%
```
[Go Blog: The cover story](https://go.dev/blog/cover)
## Inspecting code coverage
- Preview coverage as HTML page:
- **`go tool cover -html $PROFILE_NAME`**
.image assets/lecture-05/testing/html-coverage-profile.png 350 _
## Fuzzing
- As mentioned, the standard library also provides means to do fuzz testing
- TLDR; automated input generating for tests
- Like regural tests, fuzz tests are located in files with **`_test.go`** suffix
- The fuzz test functions:
- Are preffixed with **`Fuzz`** instead of **`Test`**
- Require **`*testing.F`** argument instead of **`*testing.T`**
## The F type
- The F type API is similar to the T type with multiple additions
- **`Add`**: seeds the fuzzing corpus with the given arguments
- The argument types must match the fuzz target
- **`Fuzz`**: runs the fuzz function
- If the fuzz function fails on an input it gets added to the seed corpus
- The fuzz function takes in **`*testing.T`** as the first arguments
- Rest of the arguments are fuzzed
- Supports most of basic data types as of Go 1.22
```
f.Fuzz(func(t *testing.T, b []byte, i int) { ... })
```
[Go Blog: Go fuzzing](https://go.dev/doc/security/fuzz/)
## Fuzzing example
.code assets/lecture-05/testing/fuzzing-add_test.go /START OMIT/,/END OMIT/
- Can easily be run using the go toolkit
- **`go test -fuzz FuzzAdd -fuzztime 5s`**
```
fuzz: elapsed: 0s, gathering baseline coverage: 0/5 completed
fuzz: elapsed: 0s, gathering baseline coverage: 5/5 completed, now fuzzing with 12 workers
fuzz: elapsed: 3s, execs: 1406894 (468956/sec), new interesting: 1 (total: 6)
fuzz: elapsed: 5s, execs: 2376335 (461973/sec), new interesting: 1 (total: 6)
PASS
ok test/internal/numbers 5.202s
```
## Fuzzing
- The newly discovered faulty inputs get saved
- Are then run with regular tests
- Serve as regression tests
```
numbers/
├── testdata/fuzz/FuzzAdd/a52d19fe334f7cf8
├── numbers.go
└── numbers_test.go
```
```
go test fuzz v1
int(-9)
int(-8)
```
## Third party libraries
## Assertions
## Assertions
- Go does not have an `assert` keyword
- But assert-like functions and methods exist
- Multiple third party libraries
- The [stretchr/testify](https://github.com/stretchr/testify) is the most used
- [gotestyourself/gotest.tools](https://github.com/gotestyourself/gotest.tools)
- [alecthomas/assert](https://github.com/alecthomas/assert)
## Assertions
.code assets/lecture-05/testing/recursive-factorial.go /START OMIT/,/END OMIT/
## Assertions
.code assets/lecture-05/testing/asserts-factorial_test.go /START OMIT/,/END OMIT/
## Dot import
.code assets/lecture-05/testing/asserts-factorial-dot-import_test.go /START OMIT/,/END OMIT/
## goconvey
## goconvey
- Behavior-driven development (BDD) framework
- Aims to close the gap between business people and developers
- Simple domain-specific language (DSL)
- Integrates with `go test`
- Test steps are written directly as Go source code
- Self-documenting tests
- Includes test code generator
- Tests are automatically run on save
- Supports an interactive Web UI
- Displays test coverage
[GitHub: goconvey](https://github.com/smartystreets/goconvey)
## goconvey DSL
- **`Convey`**: used to define a new scope of a test
- **`So`**: used to define assertions
- Assertions:
- **`ShouldEqual`**
- **`ShouldNotEqual`**
- **`ShouldBeBetween`**
- **`ShouldNotBeEmpty`**
- **`ShouldBeNil`**
- ...
[GitHub: goconvey assertions](https://github.com/smartystreets/goconvey/wiki/Assertions)
## goconvey factorial tests
.code assets/lecture-05/goconvey/factorial_test.go /START OMIT/,/END OMIT/
## goconvey slice tests
.code assets/lecture-05/goconvey/slice_test.go /START OMIT/,/END OMIT/
## godog
## godog
- Again, a BDD framework
- Based on the **Gherkin** language
[GitHub: godog](https://github.com/cucumber/godog)
## Gherkin language
- Based on natural language with a multiple keywords
- English is usually used
- Can be translated into [other languages](https://cucumber.io/docs/gherkin/reference/#spoken-languages) as well
- It is not tightly bound with any real programming language
- It can be used by non-developers
[Cucumber: Gherkin Reference](https://cucumber.io/docs/gherkin/reference/)
## Gherkin keywords
- **`Feature`**: high-level description of software feature
- **`Rule`**: represents a business rule
- **`Example/Examples`**: concrete example of a business rule
- **`Scenario/Scenarios`**: synonym for example
- **`Scenario Outline/Template`**: used to trigger a single scenario with multiple inputs
- **`Background`**: specifies "before-each" steps for each example
- Steps:
- **`Given`**: puts the system in a known state
- **`When`**: represents an action
- **`Then`**: represents expected outcome
- **`And/But`**: used to chain steps
## Gherkin language example
.code assets/lecture-05/godog/godogs.feature
## godog example (1/2)
.code assets/lecture-05/godog/godogs_test.go /START OMIT/,/MIDDLE OMIT/
## godog example (2/2)
.code assets/lecture-05/godog/godogs_test.go /TEST OMIT/,/END OMIT/
## Scenario Outline
.code assets/lecture-05/godog/scenario-outline.feature
## Expect
## Expect-like framework and libraries
- Originally [an extension](https://en.wikipedia.org/wiki/Expect) to the [TCL scripting language](https://en.wikipedia.org/wiki/Tcl)
- Written by [Don Libes](https://en.wikipedia.org/wiki/Don_Libes) for Unix
- Then ported to other operation systems
- Automates interactions with programs that expose a text terminal interface
- Also used to test applications such as:
- Telnet, FTP, passwd, fsck, rlogin, tip, SSH
- Used heavily in telecommunications
- Go libraries:
- [goexpect](https://github.com/google/goexpect) by Google, archived in 2023
- [go-expect](https://github.com/Netflix/go-expect) by Netflix
- [gexpect](https://github.com/ThomasRooney/gexpect)
## go-expect
.code assets/lecture-05/go-expect/curl.go /START OMIT/,/END OMIT/
## Mocking
## gomock
- Originally developed under [golang/mock](https://github.com/golang/mock) by Google
- Archived in June 2023
- Forked and now maintaned by Uber under [uber-go/mock](https://github.com/uber-go/mock)
[Go Packages: gomock](https://pkg.go.dev/go.uber.org/mock/gomock)
## gomock usage
- Install mockgen executable:
- **`go install go.uber.org/mock/mockgen@latest`**
- Define interface to mock:
.code assets/lecture-05/gomock/interface.go
- Generate mock:
- **`mockgen -source interfaces.go -destination mock.go -package calculator`**
## gomock mock (1/2)
.code assets/lecture-05/gomock/mock.go /START OMIT/,/MIDDLE OMIT/
## gomock mock (2/2)
.code assets/lecture-05/gomock/mock.go /MIDDLE OMIT/,/END OMIT/
## gomock testing with mock
.code assets/lecture-05/gomock/calculator_test.go /START OMIT/,/END OMIT/
## Utilities
## go-carpet
- Tool for displaying code coverage in your terminal
- Can display colours with `-256colours` option
- Usage:
- Run **`go-carpet -256colors`** in your project
[GitHub: go-carpet](https://github.com/msoap/go-carpet)
## gotestsum
- Tool for extending `go test` with various output formats and behavior
- JSON, JUNIT XML outputs
- Watch for changes
- Automatically runs tests
[GitHub: gotestsum](https://github.com/gotestyourself/gotestsum)