{"id":321975,"date":"2021-04-23T15:00:49","date_gmt":"2021-04-23T15:00:49","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=321975"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=321975","title":{"rendered":"\u041f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0438 \u043f\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044e \u0442\u0435\u0441\u0442\u043e\u0432 \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u0445 \u043d\u0430 Go"},"content":{"rendered":"\n<div class=\"post__text post__text_v2\" id=\"post-content-body\">\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/6a7\/0a6\/a7d\/6a70a6a7d56aaf865c15e5dc7a4f964e.png\" width=\"1200\" height=\"630\"><figcaption><\/figcaption><\/figure>\n<p>\u0412 \u043d\u0430\u0448\u0435\u0439 \u043a\u043e\u043c\u043f\u0430\u043d\u0438\u0438 \u0432 \u0441\u0442\u0435\u043a\u0435 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0435\u0441\u0442\u044c \u044f\u0437\u044b\u043a Go. \u0418 \u0438\u043d\u043e\u0433\u0434\u0430,&nbsp;\u043f\u0440\u0438 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0438 unit-\u0442\u0435\u0441\u0442\u043e\u0432 \u043a \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u043c \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u043c \u043d\u0430 Go, \u0443 \u043d\u0430\u0441 \u043f\u043e\u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0441\u043b\u043e\u0436\u043d\u043e\u0441\u0442\u0438. \u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043c\u044b \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0435\u043c \u043e \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043c\u043e\u043c\u0435\u043d\u0442\u0430\u0445, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u044b \u0443\u0447\u0438\u0442\u044b\u0432\u0430\u0435\u043c \u043f\u0440\u0438 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0438 \u0442\u0435\u0441\u0442\u043e\u0432. \u041d\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u0430\u0445 \u0440\u0430\u0437\u0431\u0435\u0440\u0451\u043c \u043a\u0430\u043a \u0438\u0445 \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c.    <\/p>\n<h4>\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u044b \u043f\u0440\u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435<\/h4>\n<p>\u041e\u0431 \u044d\u0442\u043e\u043c \u0433\u043e\u0432\u043e\u0440\u0438\u0442\u0441\u044f \u0432 \u043a\u0430\u0436\u0434\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043f\u0440\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0438 \u0442\u0435\u0441\u0442\u043e\u0432, \u0438 \u044d\u0442\u0430 \u043d\u0435 \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435\u043c. \u0418\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u044b \u0443\u043c\u0435\u043d\u044c\u0448\u0430\u044e\u0442 \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u043e\u0441\u0442\u044c \u043c\u0435\u0436\u0434\u0443 \u043f\u0430\u043a\u0435\u0442\u0430\u043c\u0438. \u041d\u043e \u0433\u043b\u0430\u0432\u043d\u043e\u0435 \u0438\u0445 \u043f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432\u043e \u043f\u0440\u0438 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0438 \u0442\u0435\u0441\u0442\u043e\u0432 \u0437\u0430\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u044b \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0442 \u043c\u043e\u043a\u0430\u0442\u044c \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0435\u0441\u0442\u044c \u0443 \u043d\u0430\u0441 \u0444\u0443\u043d\u043a\u0446\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0433\u043e Redis \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u043a\u0430\u043a\u043e\u0435-\u0442\u043e \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u043e \u0441\u0432\u043e\u0435\u0439 \u0440\u0430\u0431\u043e\u0442\u0435:<\/p>\n<pre><code class=\"go\">package yourpackage   import (     \"context\"       \"github.com\/go-redis\/redis\/v8\" )   func CheckLen(ctx context.Context, client *redis.Client, key string) bool {     val, err := client.Get(ctx, key).Result()     if err != nil {    \t return false     }     return len(val) &lt; 10   }<\/code><\/pre>\n<p>\u0422\u0435\u0441\u0442\u044b \u0434\u043b\u044f \u043d\u0435\u0451 \u043c\u043e\u0433\u0443\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0442\u0430\u043a:&nbsp;<\/p>\n<pre><code class=\"go\">package yourpackage   import (     \"context\"     \"testing\"       \"github.com\/go-redis\/redis\/v8\" )   func TestCheckLen(t *testing.T) {     ctx := context.Background()     rdb := redis.NewClient(&amp;redis.Options{Addr: \"localhost:6379\"})     err := rdb.Set(ctx, \"some_key\", \"value\", 0).Err()     if err != nil {    \t t.Fatalf(\"redis return error: %s\", err)     }       got := CheckLen(ctx, rdb, \"some_key\")     if !got {    \t t.Errorf(\"CheckLen return %v; want true\", got)     } }<\/code><\/pre>\n<p>\u041d\u043e \u043a\u0430\u043a \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u044e, \u043a\u043e\u0433\u0434\u0430 Redis \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043e\u0448\u0438\u0431\u043a\u0443? \u0418\u043b\u0438 \u0447\u0442\u043e \u0434\u0435\u043b\u0430\u0442\u044c, \u0435\u0441\u043b\u0438 \u043c\u044b \u043d\u0435 \u0445\u043e\u0442\u0438\u043c \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c Redis \u0432 \u043d\u0430\u0448 CI? \u0422\u043e \u0435\u0441\u0442\u044c \u043a\u0430\u043a \u043d\u0430\u043c \u0437\u0430\u043c\u043e\u043a\u0430\u0442\u044c \u0432\u044b\u0437\u043e\u0432 Redis? \u0418 \u043e\u0442\u0432\u0435\u0442 \u043d\u0430 \u044d\u0442\u0438 \u0432\u043e\u043f\u0440\u043e\u0441\u044b \u2014 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u044b!<\/p>\n<p>\u041f\u0435\u0440\u0435\u043f\u0438\u0448\u0435\u043c \u043d\u0430\u0448 \u043a\u043e\u0434 \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u043e\u0432: <\/p>\n<pre><code class=\"go\">package yourpackage   import (     \"context\"       \"github.com\/go-redis\/redis\/v8\" )   type Storage interface {     Set(ctx context.Context, key string, v interface{}) error     Get(ctx context.Context, key string) (string, error) }   type RedisStorage struct {     Redis *redis.Client }   func (rs *RedisStorage) Set(ctx context.Context, key string, v interface{}) error {     return rs.Redis.Set(ctx, key, v, 0).Err() }   func (rs *RedisStorage) Get(ctx context.Context, key string) (string, error) {     return rs.Redis.Get(ctx, key).Result() }   func CheckLen(ctx context.Context, storage Storage, key string) bool {     val, err := storage.Get(ctx, key)     if err != nil {    \t return false     }     return len(val) &lt; 10 }<\/code><\/pre>\n<p>\u0418\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u044b \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0443\u043f\u0440\u043e\u0449\u0430\u044e\u0442 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0442\u0435\u0441\u0442\u043e\u0432, \u043d\u043e \u0438 \u0432 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043e\u0431\u043b\u0435\u0433\u0447\u0430\u044e\u0442 \u043f\u0435\u0440\u0435\u0445\u043e\u0434 \u043d\u0430 \u0434\u0440\u0443\u0433\u0438\u0435 \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0438, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0437\u0430\u043c\u0435\u043d\u0443 Redis \u043d\u0430 Memcached. \u0422\u0435\u0441\u0442 \u0436\u0435 \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u043c\u043e\u043a\u0430 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0442\u0430\u043a:<\/p>\n<pre><code class=\"go\">package yourpackage   import (     \"context\"     \"testing\" )   type testRedis struct{}   func (t *testRedis) Get(ctx context.Context, key string) (string, error) {     return \"value\", nil } func (t *testRedis) Set(ctx context.Context, key string, v interface{}) error {     return nil }   func TestCheckLen(t *testing.T) { \t   ctx := context.Background()     storage := &amp;testRedis{}       got := CheckLen(ctx, storage, \"some_key\")     if !got {    \t t.Errorf(\"CheckLen return %v; want true\", got)     } }<\/code><\/pre>\n<h3>\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0433\u0435\u043d\u0435\u0440\u0430\u0442\u043e\u0440\u044b \u043c\u043e\u043a\u043e\u0432<\/h3>\n<p>\u041f\u043e\u043d\u044f\u0442\u043d\u043e\u0435 \u0434\u0435\u043b\u043e, \u0447\u0442\u043e \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0441\u043b\u0443\u0447\u0430\u044f \u043f\u0438\u0441\u0430\u0442\u044c \u0441\u0432\u043e\u0439 \u043c\u043e\u043a \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u0438\u0437\u0431\u044b\u0442\u043e\u0447\u043d\u043e. \u041c\u043e\u0436\u043d\u043e \u043f\u043e\u043f\u0440\u043e\u0431\u043e\u0432\u0430\u0442\u044c \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0443\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u044c\u043d\u044b\u0439 \u043c\u043e\u043a. \u0410 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u043f\u0440\u043e\u0431\u043e\u0432\u0430\u0442\u044c \u0435\u0433\u043e \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430. \u0421\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e \u0433\u0435\u043d\u0435\u0440\u0430\u0442\u043e\u0440\u043e\u0432 \u043c\u043e\u043a\u043e\u0432. \u041d\u0430\u043c \u043d\u0440\u0430\u0432\u0438\u0442\u0441\u044f <a href=\"https:\/\/github.com\/vektra\/mockery\"><u>https:\/\/github.com\/vektra\/mockery<\/u><\/a>.<\/p>\n<p>\u0414\u043b\u044f \u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u0432\u044b\u0448\u0435 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0442\u0435\u0441\u0442\u043e\u0432 \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u0433\u0435\u043d\u0435\u0440\u0430\u0442\u043e\u0440\u0430 \u043c\u043e\u0433\u043b\u043e \u0431\u044b \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c. \u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u043c \u043c\u043e\u043a \u0434\u043b\u044f \u043d\u0430\u0448\u0435\u0433\u043e \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430:<\/p>\n<pre><code class=\"go\">mockery --recursive=true --inpackage --name=Storage<\/code><\/pre>\n<p>\u0418 \u0434\u0430\u043b\u044c\u0448\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0435\u0433\u043e \u0432 \u0442\u0435\u0441\u0442\u0430\u0445 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<pre><code>package yourpackage import (     \"context\"     \"testing\"       mock \"github.com\/stretchr\/testify\/mock\" )   func TestCheckLen(t *testing.T) {     ctx := context.Background()       storage := new(MockStorage)     storage.On(\"Get\", mock.Anything, \"some_key\").Return(\"value\", nil)       got := CheckLen(ctx, storage, \"some_key\")     if !got {    \t t.Errorf(\"CheckLen return %v; want true\", got)     }<\/code><\/pre>\n<h3>\u041f\u0435\u0440\u0435\u0445\u0432\u0430\u0442\u044b\u0432\u0430\u0435\u043c \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435<\/h3>\n<p>\u0414\u043e\u043f\u0443\u0441\u0442\u0438\u043c \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u043a\u043e\u0434, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043b\u043e\u0433\u0438\u0440\u0443\u0435\u0442 \u0441\u0432\u043e\u0438 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u043a\u0430\u043a\u043e\u0439-\u043b\u0438\u0431\u043e \u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0435\u0439 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, Logrus.<\/p>\n<pre><code class=\"go\">package yourpackage   import (     log \"github.com\/sirupsen\/logrus\" )   func Minus(a, b int) int {     log.Infof(\"Minus(%v, %v)\", a, b)     return a - b }   func Plus(a, b int) int {     log.Infof(\"Plus(%v, %v)\", a, b)     return a + b }   func Mul(a, b int) int {     log.Infof(\"Mul(%v, %v)\", a, b)     return a + b \/\/ \u0442\u0443\u0442 \u043e\u0448\u0438\u0431\u043a\u0430 }<\/code><\/pre>\n<p>\u0418 \u0442\u0435\u0441\u0442\u044b \u043a \u044d\u0442\u043e\u043c\u0443 \u043a\u043e\u0434\u0443:  <\/p>\n<pre><code class=\"go\">package yourpackage   import \"testing\"   func TestPlus(t *testing.T) {     a, b, expected := 3, 2, 5     got := Plus(a, b)     if got != expected {    \t t.Errorf(\"Plus(%v, %v) return %v; want %v\", a, b, got, expected)     } }   func TestMinus(t *testing.T) {     a, b, expected := 3, 2, 1     got := Minus(a, b)     if got != expected {    \t t.Errorf(\"Minus(%v, %v) return %v; want %v\", a, b, got, expected)     } }   func TestMul(t *testing.T) {     a, b, expected := 3, 2, 6     got := Mul(a, b)     if got != expected {    \t t.Errorf(\"Mul(%v, %v) return %v; want %v\", a, b, got, expected)     } }<\/code><\/pre>\n<p>\u041f\u0440\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0435 \u0442\u0435\u0441\u0442\u043e\u0432 \u043c\u044b \u0432\u0438\u0434\u0438\u043c, \u043f\u043e\u043c\u0438\u043c\u043e \u043e\u0448\u0438\u0431\u043a\u0438, \u0435\u0449\u0451 \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043e\u0442 \u0434\u0440\u0443\u0433\u0438\u0445 \u0442\u0435\u0441\u0442\u043e\u0432:  <\/p>\n<pre><code class=\"go\">time=\"2021-03-22T22:09:54+03:00\" level=info msg=\"Plus(3, 2)\" time=\"2021-03-22T22:09:54+03:00\" level=info msg=\"Minus(3, 2)\" time=\"2021-03-22T22:09:54+03:00\" level=info msg=\"Mul(3, 2)\" --- FAIL: TestMul (0.00s) \tyourpackage_test.go:55: Mul(3, 2) return 5; want 6 FAIL FAIL\tgotest2\/yourpackage \t0.002s FAIL<\/code><\/pre>\n<p>\u0415\u0441\u043b\u0438 \u043a\u043e\u0434\u043e\u0432\u0430\u044f \u0431\u0430\u0437\u0430 \u0431\u043e\u043b\u044c\u0448\u0430\u044f, \u0442\u043e \u0443\u043f\u0430\u0432\u0448\u0438\u0435 \u0442\u0435\u0441\u0442\u044b \u043f\u043e\u0442\u0435\u0440\u044f\u044e\u0442\u0441\u044f \u0441\u0440\u0435\u0434\u0438 \u043b\u0438\u0448\u043d\u0435\u0433\u043e \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f. \u0427\u0442\u043e\u0431\u044b \u0442\u0430\u043a\u043e\u0433\u043e \u043d\u0435 \u0431\u044b\u043b\u043e, \u043c\u043e\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043f\u0435\u0440\u0435\u0445\u0432\u0430\u0442 \u043b\u043e\u0433\u043e\u0432 \u0432 \u0442\u0435\u0441\u0442\u0430\u0445. \u0414\u043b\u044f \u043f\u0440\u0438\u0432\u0435\u0434\u0451\u043d\u043d\u043e\u0433\u043e \u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u044d\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0432\u043e\u0442 \u0442\u0430\u043a:<\/p>\n<pre><code class=\"go\">package yourpackage   import (     \"io\"     \"testing\"       \"github.com\/sirupsen\/logrus\" )   type logCapturer struct {     *testing.T     origOut io.Writer }   func (tl logCapturer) Write(p []byte) (n int, err error) {     tl.Logf((string)(p))     return len(p), nil }   func (tl logCapturer) Release() {     logrus.SetOutput(tl.origOut) }   func CaptureLog(t *testing.T) *logCapturer {     lc := logCapturer{T: t, origOut: logrus.StandardLogger().Out}     if !testing.Verbose() {    \t logrus.SetOutput(lc)     }     return &amp;lc }   func TestPlus(t *testing.T) {     defer CaptureLog(t).Release()     a, b, expected := 3, 2, 5     got := Plus(a, b)     if got != expected {    \t t.Errorf(\"Plus(%v, %v) return %v; want %v\", a, b, got, expected)     } }   func TestMinus(t *testing.T) {     defer CaptureLog(t).Release()     a, b, expected := 3, 2, 5     got := Minus(a, b)     if got != expected {    \t t.Errorf(\"Minus(%v, %v) return %v; want %v\", a, b, got, expected)     } }   func TestMul(t *testing.T) {     defer CaptureLog(t).Release()     a, b, expected := 3, 2, 5     got := Mul(a, b)     if got != expected {    \t t.Errorf(\"Mul(%v, %v) return %v; want %v\", a, b, got, expected)     } }<\/code><\/pre>\n<p>\u0418 \u0442\u043e\u0433\u0434\u0430 \u0432\u044b\u0432\u043e\u0434 \u0442\u0435\u0441\u0442\u043e\u0432 \u0431\u0443\u0434\u0435\u0442 \u043b\u0430\u043a\u043e\u043d\u0438\u0447\u043d\u0435\u0435, \u0438 \u0441\u0440\u0430\u0437\u0443 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043d\u044f\u0442\u043d\u043e, \u043a\u0430\u043a\u043e\u0435 \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0438 \u0432 \u043a\u0430\u043a\u043e\u043c \u0442\u0435\u0441\u0442\u0435 \u0432\u0435\u043b\u043e\u0441\u044c:<\/p>\n<pre><code class=\"go\">--- FAIL: TestMul (0.00s) \tyourpackage_test.go:16: time=\"2021-03-22T22:10:52+03:00\" level=info msg=\"Mul(3, 2)\" \tyourpackage_test.go:55: Mul(3, 2) return 5; want 6 FAIL FAIL\tgotest2\/yourpackage \t0.002s FAIL<\/code><\/pre>\n<p>\u0417\u0434\u0435\u0441\u044c \u043f\u0440\u0438\u0432\u0435\u0434\u0451\u043d \u043f\u0440\u0438\u043c\u0435\u0440 \u0434\u043b\u044f Logrus, \u043d\u043e \u043d\u0435\u0447\u0442\u043e \u043f\u043e\u0445\u043e\u0436\u0435\u0435 \u043c\u043e\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0441 \u043b\u044e\u0431\u043e\u0439 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u043e\u0439 \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0434\u043b\u044f \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 Zap \u0435\u0441\u0442\u044c <a href=\"https:\/\/pkg.go.dev\/go.uber.org\/zap\/zaptest#NewLogger\"><u>\u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u043c\u043e\u0434\u0443\u043b\u044c<\/u><\/a>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u0431\u043b\u0435\u0433\u0447\u0430\u0435\u0442 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435.<\/p>\n<h3>\u0421\u0447\u0438\u0442\u0430\u0435\u043c \u043f\u043e\u043a\u0440\u044b\u0442\u0438\u0435 \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e<\/h3>\n<p>\u0412 Go \u0432\u0441\u0435\u0433\u0434\u0430 \u0431\u044b\u043b\u0430 \u043a\u0430\u043a\u0430\u044f-\u0442\u043e \u0441\u0442\u0440\u0430\u043d\u043d\u043e\u0441\u0442\u044c \u0441 \u043f\u043e\u0434\u0441\u0447\u0451\u0442\u043e\u043c \u043f\u043e\u043a\u0440\u044b\u0442\u0438\u044f \u043a\u043e\u0434\u0430 \u0442\u0435\u0441\u0442\u0430\u043c\u0438. \u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u043d\u0435\u043b\u044c\u0437\u044f \u0431\u044b\u043b\u043e \u043f\u043e\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u043e\u0442\u0447\u0451\u0442 \u043f\u043e \u043f\u043e\u043a\u0440\u044b\u0442\u0438\u044e \u0434\u043b\u044f \u0432\u0441\u0435\u0445 \u043f\u0430\u043a\u0435\u0442\u043e\u0432, \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u0445 \u0432 \u0440\u0430\u043c\u043a\u0430\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u0414\u043e \u0441\u0438\u0445 \u043f\u043e\u0440 \u0432 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f\u0445 \u043c\u043e\u0436\u043d\u043e \u0432\u0441\u0442\u0440\u0435\u0442\u0438\u0442\u044c \u0441\u043a\u0440\u0438\u043f\u0442\u044b, \u043f\u043e\u0445\u043e\u0436\u0438\u0435 \u043d\u0430 <a href=\"https:\/\/gist.github.com\/cdennison\/cba009cf297aa2a92759278b5c578ae4\"><u>\u044d\u0442\u043e\u0442<\/u><\/a>, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u0434\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0442\u0435\u0441\u0442\u043e\u0432 \u043f\u043e \u0432\u0441\u0435\u043c \u043f\u0430\u043a\u0435\u0442\u0430\u043c \u0438 \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043e \u043f\u043e\u043a\u0440\u044b\u0442\u0438\u0438 \u0432 \u043e\u0434\u0438\u043d \u043e\u0442\u0447\u0451\u0442. \u0421\u0435\u0439\u0447\u0430\u0441 \u0441 \u044d\u0442\u0438\u043c \u0432\u0441\u0451 \u0445\u043e\u0440\u043e\u0448\u043e, \u043d\u043e \u0435\u0441\u0442\u044c \u043d\u0435\u043e\u0447\u0435\u0432\u0438\u0434\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442.&nbsp;<\/p>\n<p>\u0414\u043e\u043f\u0443\u0441\u0442\u0438\u043c, \u043d\u0430\u0448 \u043f\u0440\u043e\u0435\u043a\u0442 \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0438\u0437 \u0442\u0440\u0451\u0445 \u043f\u0430\u043a\u0435\u0442\u043e\u0432. \u0418 \u043c\u044b \u0445\u043e\u0442\u0438\u043c \u0434\u043b\u044f \u043d\u0438\u0445 \u043f\u043e\u0441\u0447\u0438\u0442\u0430\u0442\u044c \u043f\u043e\u043a\u0440\u044b\u0442\u0438\u0435. \u041e\u0431\u0440\u0430\u0449\u0430\u0435\u043c\u0441\u044f \u0437\u0430 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043a \u0443\u0442\u0438\u043b\u0438\u0442\u0435 cover, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0441\u043a\u0430\u0436\u0435\u0442 \u043d\u0430\u043c \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0435:<\/p>\n<pre><code class=\"go\">$ go tool cover -help Usage of 'go tool cover': Given a coverage profile produced by 'go test':     \tgo test -coverprofile=c.out ... Display coverage percentages to stdout for each function:     \tgo tool cover -func=c.out<\/code><\/pre>\n<p>\u041f\u0440\u043e\u0431\u0443\u0435\u043c:  <\/p>\n<pre><code class=\"go\">$ go test -coverprofile=c.out .\/... ok  \tgotestcover\/minus   \t0.001s  coverage: 100.0% of statements ?   \tgotestcover\/mul [no test files] ok  \tgotestcover\/plus    \t0.001s  coverage: 100.0% of statements<\/code><\/pre>\n<p>\u0423\u0436\u0435 \u0438\u0437 \u044d\u0442\u043e\u0433\u043e \u0432\u044b\u0432\u043e\u0434\u0430 \u0432\u0438\u0434\u043d\u043e, \u0447\u0442\u043e \u0443 \u043d\u0430\u0441 \u0434\u0432\u0430 \u043f\u0430\u043a\u0435\u0442\u0430 \u043f\u043e\u043a\u0440\u044b\u0442\u044b \u043d\u0430 100 % \u0438 \u0434\u043b\u044f \u043e\u0434\u043d\u043e\u0433\u043e \u043f\u0430\u043a\u0435\u0442\u0430 \u043d\u0435\u0442 \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0445 \u0444\u0430\u0439\u043b\u043e\u0432. \u041f\u043e\u043b\u0443\u0447\u0438\u043c \u043e\u0442\u0447\u0451\u0442 \u043e \u043f\u043e\u043a\u0440\u044b\u0442\u0438\u0438:<\/p>\n<pre><code class=\"go\">$ go tool cover -func=c.out gotestcover\/minus\/minus.go:4:   Minus       \t100.0% gotestcover\/plus\/plus.go:4: \tPlus        \t100.0% total:                      \t(statements)\t100.0%<\/code><\/pre>\n<p>\u041d\u043e \u0442\u0443\u0442 \u0447\u0442\u043e-\u0442\u043e \u043d\u0435 \u0442\u0430\u043a. \u0412 \u043e\u0442\u0447\u0451\u0442\u0435 \u0433\u043e\u0432\u043e\u0440\u0438\u0442\u0441\u044f \u043e \u043f\u043e\u043b\u043d\u043e\u043c \u043f\u043e\u043a\u0440\u044b\u0442\u0438\u0438 \u0442\u0435\u0441\u0442\u0430\u043c\u0438. \u0425\u043e\u0442\u044f \u043c\u044b \u0437\u043d\u0430\u0435\u043c, \u0447\u0442\u043e \u044d\u0442\u043e \u043d\u0435 \u0442\u0430\u043a. \u042d\u0442\u043e \u0432\u0441\u0451 \u043f\u043e\u0442\u043e\u043c\u0443, \u0447\u0442\u043e \u043f\u0440\u0438 \u043f\u043e\u0434\u0441\u0447\u0451\u0442\u0435 \u043f\u043e\u043a\u0440\u044b\u0442\u0438\u044f \u043d\u0435 \u0443\u0447\u0438\u0442\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043f\u0430\u043a\u0435\u0442, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043d\u0435\u0442 \u0442\u0435\u0441\u0442\u043e\u0432. \u0415\u0433\u043e \u043d\u0435 \u0431\u0443\u0434\u0435\u0442 \u0438 \u0432 HTML-\u043e\u0442\u0447\u0451\u0442\u0435. \u0418 \u043a\u0430\u0436\u0435\u0442\u0441\u044f, \u0447\u0442\u043e \u044d\u0442\u043e \u043d\u0435 \u0432\u0441\u0435\u0433\u0434\u0430 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u044b\u043c, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u0437\u0430\u0447\u0430\u0441\u0442\u0443\u044e \u043c\u044b \u0445\u043e\u0442\u0438\u043c \u0437\u043d\u0430\u0442\u044c \u043f\u043e\u043a\u0440\u044b\u0442\u0438\u0435 \u0432\u0441\u0435\u0433\u043e \u043a\u043e\u0434\u0430, \u0430 \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0442\u043e\u0433\u043e, \u0434\u043b\u044f \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u043c\u044b \u043d\u0430\u043f\u0438\u0441\u0430\u043b\u0438 \u0442\u0435\u0441\u0442\u044b. \u042d\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u0440\u0430\u0432\u0438\u0442\u044c, \u0443\u043a\u0430\u0437\u0430\u0432 \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0439 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 \u043f\u0440\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0435 \u0442\u0435\u0441\u0442\u043e\u0432:<\/p>\n<pre><code class=\"go\">go test -coverpkg=.\/... -coverprofile=c.out .\/\u2026<\/code><\/pre>\n<p>\u0418 \u0442\u0435\u043f\u0435\u0440\u044c \u043e\u0442\u0447\u0451\u0442 \u0432\u044b\u0434\u0430\u0451\u0442 \u043e\u0436\u0438\u0434\u0430\u0435\u043c\u044b\u0439 \u043f\u0440\u043e\u0446\u0435\u043d\u0442 \u043f\u043e\u043a\u0440\u044b\u0442\u0438\u044f \u0442\u0435\u0441\u0442\u0430\u043c\u0438:<\/p>\n<pre><code class=\"go\">$ go tool cover -func=c.out gotestcover\/minus\/minus.go:4:   Minus       \t100.0% gotestcover\/mul\/mul.go:4:   \tMul         \t0.0% gotestcover\/plus\/plus.go:4: \tPlus        \t100.0% total:                      \t(statements)\t66.7%<\/code><\/pre>\n<h3>\u0421\u0447\u0438\u0442\u0430\u0435\u043c \u043f\u043e\u043a\u0440\u044b\u0442\u0438\u0435 \u043f\u0440\u0438 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043a\u0430\u043a \u0447\u0435\u0440\u043d\u043e\u0433\u043e \u044f\u0449\u0438\u043a\u0430<\/h3>\n<p>\u041f\u0438\u0441\u0430\u0442\u044c \u0442\u0435\u0441\u0442\u044b \u043d\u0430 Go \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e-\u0442\u0430\u043a\u0438 \u0441\u043b\u043e\u0436\u043d\u043e. \u0418 \u0435\u0441\u043b\u0438 \u0432\u044b \u0440\u0430\u0437\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442\u0435 \u043a\u0430\u043a\u043e\u0439-\u043d\u0438\u0431\u0443\u0434\u044c \u0432\u0435\u0431-\u0441\u0435\u0440\u0432\u0438\u0441, \u0442\u043e \u0438\u043d\u043e\u0433\u0434\u0430 \u0431\u044b\u0432\u0430\u0435\u0442 \u043f\u0440\u043e\u0449\u0435 \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0442\u0435\u0441\u0442\u044b \u043d\u0430 \u0434\u0440\u0443\u0433\u043e\u043c \u044f\u0437\u044b\u043a\u0435, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043d\u0430 Python, \u0438 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043a\u0430\u043a \u00ab\u0447\u0451\u0440\u043d\u044b\u0439 \u044f\u0449\u0438\u043a\u00bb.&nbsp;<\/p>\n<p>\u041d\u043e \u0432\u043e\u0437\u043d\u0438\u043a\u0430\u0435\u0442 \u0432\u043e\u043f\u0440\u043e\u0441, \u0430 \u043c\u043e\u0436\u043d\u043e \u043b\u0438 \u043f\u043e\u0441\u0447\u0438\u0442\u0430\u0442\u044c \u043f\u043e\u043a\u0440\u044b\u0442\u0438\u0435 \u0434\u043b\u044f \u0442\u0430\u043a\u043e\u0433\u043e \u0441\u043f\u043e\u0441\u043e\u0431\u0430 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f? \u0414\u0430, \u043f\u043e\u0441\u0447\u0438\u0442\u0430\u0442\u044c \u043c\u043e\u0436\u043d\u043e. \u0412 \u0446\u0435\u043b\u043e\u043c, \u0438\u0434\u0435\u044f \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u0430. \u041f\u0438\u0448\u0435\u043c \u043f\u043e\u0434\u043e\u0431\u043d\u044b\u0439 \u0442\u0435\u0441\u0442:&nbsp;<\/p>\n<pre><code class=\"go\">func TestRunMain(t *testing.T) {     \tmain() }<\/code><\/pre>\n<p>\u0417\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c \u0435\u0433\u043e, \u043f\u043e\u0442\u043e\u043c \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0435 \u0442\u0435\u0441\u0442\u044b, \u0438 \u0437\u0430\u0432\u0435\u0440\u0448\u0430\u0435\u043c \u043d\u0430\u0448 \u0442\u0435\u0441\u0442. \u0417\u0432\u0443\u0447\u0438\u0442 \u043f\u0440\u043e\u0441\u0442\u043e, \u043d\u043e \u0435\u0441\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043d\u044e\u0430\u043d\u0441\u043e\u0432. \u0417\u0430\u0447\u0430\u0441\u0442\u0443\u044e \u043d\u0430\u0434\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0442\u0430\u043a, \u0447\u0442\u043e\u0431\u044b \u044d\u0442\u043e\u0442 \u0442\u0435\u0441\u0442 \u043d\u0435 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u043b\u0441\u044f \u0441\u043e \u0432\u0441\u0435\u043c\u0438 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u043c\u0438 \u0442\u0435\u0441\u0442\u0430\u043c\u0438. \u041e\u043d \u043e\u0441\u043e\u0431\u044b\u0439, \u0438 \u0434\u043b\u044f \u043d\u0435\u0433\u043e \u0434\u043e\u043b\u0436\u043d\u0430 \u0431\u044b\u0442\u044c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u0430\u044f \u043b\u043e\u0433\u0438\u043a\u0430 \u0437\u0430\u043f\u0443\u0441\u043a\u0430. \u0415\u0449\u0451 \u0444\u0443\u043d\u043a\u0446\u0438\u044f <code>main<\/code> \u043d\u0435 \u0434\u043e\u043b\u0436\u043d\u0430 \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u0442\u044c \u043a \u0432\u044b\u0445\u043e\u0434\u0443 \u0441 \u043d\u0435\u043d\u0443\u043b\u0435\u0432\u044b\u043c \u043a\u043e\u0434\u043e\u043c \u0432\u043e\u0437\u0432\u0440\u0430\u0442\u0430. \u0418 \u043d\u0430\u0434\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0441\u043f\u043e\u0441\u043e\u0431 \u0432\u044b\u0445\u043e\u0434\u0430 \u0438\u0437 <code>main<\/code> \u043f\u043e \u0441\u0438\u0433\u043d\u0430\u043b\u0443, \u043d\u0435 \u0437\u0430\u0432\u0435\u0440\u0448\u0430\u044f \u043f\u0440\u0438 \u044d\u0442\u043e\u043c \u0441\u0430\u043c \u0442\u0435\u0441\u0442. \u0422\u043e \u0435\u0441\u0442\u044c \u0432 \u0446\u0435\u043b\u043e\u043c \u043d\u0430\u0434\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f \u043d\u0430\u0448\u0435\u0433\u043e web-\u0441\u0435\u0440\u0432\u0438\u0441\u0430 graceful shutdown, \u0447\u0442\u043e \u043d\u0435\u0441\u043b\u043e\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c, \u0438 \u044d\u0442\u043e \u0432 \u0446\u0435\u043b\u043e\u043c \u043f\u043e\u043b\u0435\u0437\u043d\u043e. \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u043d\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 web-\u0441\u0435\u0440\u0432\u0438\u0441, \u043f\u0440\u043e\u0442\u0435\u0441\u0442\u0438\u0440\u0443\u0435\u043c \u0435\u0433\u043e \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e curl, \u0438 \u043f\u043e\u0441\u0447\u0438\u0442\u0430\u0435\u043c \u043f\u043e\u043a\u0440\u044b\u0442\u0438\u0435 \u0442\u0435\u0441\u0442\u0430\u043c\u0438.&nbsp;<\/p>\n<p>\u0421\u0435\u0440\u0432\u0438\u0441 \u043d\u0430\u0448 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c (\u0432\u0437\u044f\u0442\u043e \u0441 https:\/\/gobyexample.com\/http-servers):<\/p>\n<pre><code class=\"go\">package main   import (     \"context\"     \"fmt\"     \"net\/http\"     \"os\"     \"os\/signal\"     \"time\" )   func hello(w http.ResponseWriter, req *http.Request) {     fmt.Fprintf(w, \"hello\\n\") }   func headers(w http.ResponseWriter, req *http.Request) {     for name, headers := range req.Header {    \t for _, h := range headers {    \t\t fmt.Fprintf(w, \"%v: %v\\n\", name, h)    \t }     } }   func main() {     http.HandleFunc(\"\/hello\", hello)     http.HandleFunc(\"\/headers\", headers)       \/\/ \u041f\u0440\u0438\u043b\u043e\u0436\u0438\u043c \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0443\u0441\u0438\u043b\u0438\u044f, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u043b\u043e\u0441\u044c \u0441 \u043d\u0443\u043b\u0435\u0432\u044b\u043c \u043a\u043e\u0434\u043e\u043c \u0432\u044b\u0445\u043e\u0434\u0430     \/\/ \u042d\u0442\u043e \u0432\u0430\u0436\u043d\u043e \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u043e\u0432, \u0438 \u0432 \u0446\u0435\u043b\u043e\u043c \u043f\u0440\u0438\u044f\u0442\u043d\u043e     server := &amp;http.Server{Addr: \":8090\", Handler: nil}     \/\/ \u0417\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u0439 \u0433\u043e\u0440\u0443\u0442\u0438\u043d\u0435     go func() {    \t server.ListenAndServe()     }()       \/\/ \u0410 \u0432 \u0442\u0435\u043a\u0443\u0449\u0435\u0439 \u0436\u0434\u0451\u043c \u0441\u0438\u0433\u043d\u0430\u043b\u0430 \u043e\u0431 \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f     quit := make(chan os.Signal, 1)     signal.Notify(quit, os.Interrupt)     &lt;-quit     ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)     defer cancel()     server.Shutdown(ctx) }<\/code><\/pre>\n<p>\u0418 \u0442\u0435\u0441\u0442 \u043a \u043d\u0435\u043c\u0443:  <\/p>\n<pre><code class=\"go\">\/\/ +build testrunmain   package main   import \"testing\"   func TestRunMain(t *testing.T) {     main() }<\/code><\/pre>\n<p>\u041a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0439 <code>+build testrunmain<\/code> \u0433\u043e\u0432\u043e\u0440\u0438\u0442 \u043e \u0442\u043e\u043c, \u0447\u0442\u043e \u0442\u0435\u0441\u0442 \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0432 \u0441\u043b\u0443\u0447\u0430\u0435, \u0435\u0441\u043b\u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u043d \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0439 tag. \u0417\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c \u043d\u0430\u0448 \u0442\u0435\u0441\u0442:<\/p>\n<pre><code class=\"go\">$ go test -v -tags testrunmain -coverpkg=.\/... -coverprofile=c.out  .\/... === RUN   TestRunMain<\/code><\/pre>\n<p>\u0422\u0435\u0441\u0442\u0438\u0440\u0443\u0435\u043c \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e curl:<\/p>\n<pre><code class=\"go\">$ curl 127.0.0.1:8090\/hello hello<\/code><\/pre>\n<p>\u0418 \u0437\u0430\u0432\u0435\u0440\u0448\u0430\u0435\u043c \u043d\u0430\u0448\u0435 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435, \u043d\u0430\u0436\u0430\u0432 Ctrl+C:<\/p>\n<pre><code class=\"go\">$ go test -v -tags testrunmain -coverpkg=.\/... -coverprofile=c.out  .\/... === RUN   TestRunMain ^C--- PASS: TestRunMain (100.92s) PASS coverage: 80.0% of statements in .\/... ok  \tgobintest   \t100.926s    \tcoverage: 80.0% of statements in .\/\u2026<\/code><\/pre>\n<p>\u041c\u043e\u0436\u0435\u043c \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u043f\u043e\u043a\u0440\u044b\u0442\u0438\u0435 \u0442\u0435\u0441\u0442\u0430\u043c\u0438 \u0438 \u0443\u0432\u0438\u0434\u0435\u0442\u044c, \u0447\u0442\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a <code>headers <\/code>\u043e\u0441\u0442\u0430\u043b\u0441\u044f \u043d\u0435 \u043f\u0440\u043e\u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u043c:<\/p>\n<pre><code class=\"go\">$ go tool cover -func=c.out gobintest\/main.go:12:   hello       \t100.0% gobintest\/main.go:16:   headers     \t0.0% gobintest\/main.go:24:   main        \t100.0% total:              \t(statements)\t80.0%<\/code><\/pre>\n<p>\u041c\u044b \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u043b\u0438 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0432\u043e\u043f\u0440\u043e\u0441\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0432\u043e\u0437\u043d\u0438\u043a\u0430\u043b\u0438 \u0443 \u043d\u0430\u0441 \u0432 \u043a\u043e\u043c\u043f\u0430\u043d\u0438\u0438, \u043a\u043e\u0433\u0434\u0430 \u0440\u0435\u0447\u044c \u0437\u0430\u0445\u043e\u0434\u0438\u043b\u0430 \u043e \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u043d\u0430 Go. \u041d\u0430\u0434\u0435\u0435\u043c\u0441\u044f, \u0447\u0442\u043e \u0441\u0442\u0430\u0442\u044c\u044f \u0431\u0443\u0434\u0435\u0442 \u0432\u0430\u043c \u043f\u043e\u043b\u0435\u0437\u043d\u0430.&nbsp;<\/p>\n<p>\u0425\u043e\u0442\u0438\u0442\u0435 \u0443\u0437\u043d\u0430\u0442\u044c \u0431\u043e\u043b\u044c\u0448\u0435 \u043e \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438 \u0432 Go? \u0412\u043e\u0442 \u0435\u0449\u0451 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b\u0445 \u0441\u0442\u0430\u0442\u0435\u0439 \u043d\u0430 \u0445\u0430\u0431\u0440\u0435: <a href=\"https:\/\/habr.com\/ru\/post\/520278\/\"><u>\u043e\u0434\u0438\u043d<\/u><\/a>, <a href=\"https:\/\/habr.com\/ru\/company\/otus\/blog\/452772\/\"><u>\u0434\u0432\u0430<\/u><\/a>, <a href=\"https:\/\/habr.com\/ru\/post\/425025\/\"><u>\u0442\u0440\u0438<\/u><\/a>. <\/p>\n<\/div>\n<p> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/company\/ivi\/blog\/553970\/\"> https:\/\/habr.com\/ru\/company\/ivi\/blog\/553970\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"\n<div class=\"post__text post__text_v2\" id=\"post-content-body\">\n<figure class=\"\"><figcaption><\/figcaption><\/figure>\n<p>\u0412 \u043d\u0430\u0448\u0435\u0439 \u043a\u043e\u043c\u043f\u0430\u043d\u0438\u0438 \u0432 \u0441\u0442\u0435\u043a\u0435 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0435\u0441\u0442\u044c \u044f\u0437\u044b\u043a Go. \u0418 \u0438\u043d\u043e\u0433\u0434\u0430,&nbsp;\u043f\u0440\u0438 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0438 unit-\u0442\u0435\u0441\u0442\u043e\u0432 \u043a \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u043c \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u043c \u043d\u0430 Go, \u0443 \u043d\u0430\u0441 \u043f\u043e\u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0441\u043b\u043e\u0436\u043d\u043e\u0441\u0442\u0438. \u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043c\u044b \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0435\u043c \u043e \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043c\u043e\u043c\u0435\u043d\u0442\u0430\u0445, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u044b \u0443\u0447\u0438\u0442\u044b\u0432\u0430\u0435\u043c \u043f\u0440\u0438 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0438 \u0442\u0435\u0441\u0442\u043e\u0432. \u041d\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u0430\u0445 \u0440\u0430\u0437\u0431\u0435\u0440\u0451\u043c \u043a\u0430\u043a \u0438\u0445 \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c.    <\/p>\n<h4>\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u044b \u043f\u0440\u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435<\/h4>\n<p>\u041e\u0431 \u044d\u0442\u043e\u043c \u0433\u043e\u0432\u043e\u0440\u0438\u0442\u0441\u044f \u0432 \u043a\u0430\u0436\u0434\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043f\u0440\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0438 \u0442\u0435\u0441\u0442\u043e\u0432, \u0438 \u044d\u0442\u0430 \u043d\u0435 \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435\u043c. \u0418\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u044b \u0443\u043c\u0435\u043d\u044c\u0448\u0430\u044e\u0442 \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u043e\u0441\u0442\u044c \u043c\u0435\u0436\u0434\u0443 \u043f\u0430\u043a\u0435\u0442\u0430\u043c\u0438. \u041d\u043e \u0433\u043b\u0430\u0432\u043d\u043e\u0435 \u0438\u0445 \u043f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432\u043e \u043f\u0440\u0438 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0438 \u0442\u0435\u0441\u0442\u043e\u0432 \u0437\u0430\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u044b \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0442 \u043c\u043e\u043a\u0430\u0442\u044c \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0435\u0441\u0442\u044c \u0443 \u043d\u0430\u0441 \u0444\u0443\u043d\u043a\u0446\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0433\u043e Redis \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u043a\u0430\u043a\u043e\u0435-\u0442\u043e \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u043e \u0441\u0432\u043e\u0435\u0439 \u0440\u0430\u0431\u043e\u0442\u0435:<\/p>\n<pre><code class=\"go\">package yourpackage   import (     \"context\"       \"github.com\/go-redis\/redis\/v8\" )   func CheckLen(ctx context.Context, client *redis.Client, key string) bool {     val, err := client.Get(ctx, key).Result()     if err != nil {    \t return false     }     return len(val) &lt; 10   }<\/code><\/pre>\n<p>\u0422\u0435\u0441\u0442\u044b \u0434\u043b\u044f \u043d\u0435\u0451 \u043c\u043e\u0433\u0443\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0442\u0430\u043a:&nbsp;<\/p>\n<pre><code class=\"go\">package yourpackage   import (     \"context\"     \"testing\"       \"github.com\/go-redis\/redis\/v8\" )   func TestCheckLen(t *testing.T) {     ctx := context.Background()     rdb := redis.NewClient(&amp;redis.Options{Addr: \"localhost:6379\"})     err := rdb.Set(ctx, \"some_key\", \"value\", 0).Err()     if err != nil {    \t t.Fatalf(\"redis return error: %s\", err)     }       got := CheckLen(ctx, rdb, \"some_key\")     if !got {    \t t.Errorf(\"CheckLen return %v; want true\", got)     } }<\/code><\/pre>\n<p>\u041d\u043e \u043a\u0430\u043a \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u044e, \u043a\u043e\u0433\u0434\u0430 Redis \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043e\u0448\u0438\u0431\u043a\u0443? \u0418\u043b\u0438 \u0447\u0442\u043e \u0434\u0435\u043b\u0430\u0442\u044c, \u0435\u0441\u043b\u0438 \u043c\u044b \u043d\u0435 \u0445\u043e\u0442\u0438\u043c \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c Redis \u0432 \u043d\u0430\u0448 CI? \u0422\u043e \u0435\u0441\u0442\u044c \u043a\u0430\u043a \u043d\u0430\u043c \u0437\u0430\u043c\u043e\u043a\u0430\u0442\u044c \u0432\u044b\u0437\u043e\u0432 Redis? \u0418 \u043e\u0442\u0432\u0435\u0442 \u043d\u0430 \u044d\u0442\u0438 \u0432\u043e\u043f\u0440\u043e\u0441\u044b \u2014 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u044b!<\/p>\n<p>\u041f\u0435\u0440\u0435\u043f\u0438\u0448\u0435\u043c \u043d\u0430\u0448 \u043a\u043e\u0434 \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u043e\u0432: <\/p>\n<pre><code class=\"go\">package yourpackage   import (     \"context\"       \"github.com\/go-redis\/redis\/v8\" )   type Storage interface {     Set(ctx context.Context, key string, v interface{}) error     Get(ctx context.Context, key string) (string, error) }   type RedisStorage struct {     Redis *redis.Client }   func (rs *RedisStorage) Set(ctx context.Context, key string, v interface{}) error {     return rs.Redis.Set(ctx, key, v, 0).Err() }   func (rs *RedisStorage) Get(ctx context.Context, key string) (string, error) {     return rs.Redis.Get(ctx, key).Result() }   func CheckLen(ctx context.Context, storage Storage, key string) bool {     val, err := storage.Get(ctx, key)     if err != nil {    \t return false     }     return len(val) &lt; 10 }<\/code><\/pre>\n<p>\u0418\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u044b \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0443\u043f\u0440\u043e\u0449\u0430\u044e\u0442 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0442\u0435\u0441\u0442\u043e\u0432, \u043d\u043e \u0438 \u0432 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043e\u0431\u043b\u0435\u0433\u0447\u0430\u044e\u0442 \u043f\u0435\u0440\u0435\u0445\u043e\u0434 \u043d\u0430 \u0434\u0440\u0443\u0433\u0438\u0435 \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0438, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0437\u0430\u043c\u0435\u043d\u0443 Redis \u043d\u0430 Memcached. \u0422\u0435\u0441\u0442 \u0436\u0435 \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u043c\u043e\u043a\u0430 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0442\u0430\u043a:<\/p>\n<pre><code class=\"go\">package yourpackage   import (     \"context\"     \"testing\" )   type testRedis struct{}   func (t *testRedis) Get(ctx context.Context, key string) (string, error) {     return \"value\", nil } func (t *testRedis) Set(ctx context.Context, key string, v interface{}) error {     return nil }   func TestCheckLen(t *testing.T) { \t   ctx := context.Background()     storage := &amp;testRedis{}       got := CheckLen(ctx, storage, \"some_key\")     if !got {    \t t.Errorf(\"CheckLen return %v; want true\", got)     } }<\/code><\/pre>\n<h3>\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0433\u0435\u043d\u0435\u0440\u0430\u0442\u043e\u0440\u044b \u043c\u043e\u043a\u043e\u0432<\/h3>\n<p>\u041f\u043e\u043d\u044f\u0442\u043d\u043e\u0435 \u0434\u0435\u043b\u043e, \u0447\u0442\u043e \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0441\u043b\u0443\u0447\u0430\u044f \u043f\u0438\u0441\u0430\u0442\u044c \u0441\u0432\u043e\u0439 \u043c\u043e\u043a \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u0438\u0437\u0431\u044b\u0442\u043e\u0447\u043d\u043e. \u041c\u043e\u0436\u043d\u043e \u043f\u043e\u043f\u0440\u043e\u0431\u043e\u0432\u0430\u0442\u044c \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0443\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u044c\u043d\u044b\u0439 \u043c\u043e\u043a. \u0410 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u043f\u0440\u043e\u0431\u043e\u0432\u0430\u0442\u044c \u0435\u0433\u043e \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430. \u0421\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e \u0433\u0435\u043d\u0435\u0440\u0430\u0442\u043e\u0440\u043e\u0432 \u043c\u043e\u043a\u043e\u0432. \u041d\u0430\u043c \u043d\u0440\u0430\u0432\u0438\u0442\u0441\u044f <a href=\"https:\/\/github.com\/vektra\/mockery\"><u>https:\/\/github.com\/vektra\/mockery<\/u><\/a>.<\/p>\n<p>\u0414\u043b\u044f \u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u0432\u044b\u0448\u0435 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0442\u0435\u0441\u0442\u043e\u0432 \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u0433\u0435\u043d\u0435\u0440\u0430\u0442\u043e\u0440\u0430 \u043c\u043e\u0433\u043b\u043e \u0431\u044b \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c. \u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u043c \u043c\u043e\u043a \u0434\u043b\u044f \u043d\u0430\u0448\u0435\u0433\u043e \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430:<\/p>\n<pre><code class=\"go\">mockery --recursive=true --inpackage --name=Storage<\/code><\/pre>\n<p>\u0418 \u0434\u0430\u043b\u044c\u0448\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0435\u0433\u043e \u0432 \u0442\u0435\u0441\u0442\u0430\u0445 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<pre><code>package yourpackage import (     \"context\"     \"testing\"       mock \"github.com\/stretchr\/testify\/mock\" )   func TestCheckLen(t *testing.T) {     ctx := context.Background()       storage := new(MockStorage)     storage.On(\"Get\", mock.Anything, \"some_key\").Return(\"value\", nil)       got := CheckLen(ctx, storage, \"some_key\")     if !got {    \t t.Errorf(\"CheckLen return %v; want true\", got)     }<\/code><\/pre>\n<h3>\u041f\u0435\u0440\u0435\u0445\u0432\u0430\u0442\u044b\u0432\u0430\u0435\u043c \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435<\/h3>\n<p>\u0414\u043e\u043f\u0443\u0441\u0442\u0438\u043c \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u043a\u043e\u0434, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043b\u043e\u0433\u0438\u0440\u0443\u0435\u0442 \u0441\u0432\u043e\u0438 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u043a\u0430\u043a\u043e\u0439-\u043b\u0438\u0431\u043e \u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0435\u0439 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, Logrus.<\/p>\n<pre><code class=\"go\">package yourpackage   import (     log \"github.com\/sirupsen\/logrus\" )   func Minus(a, b int) int {     log.Infof(\"Minus(%v, %v)\", a, b)     return a - b }   func Plus(a, b int) int {     log.Infof(\"Plus(%v, %v)\", a, b)     return a + b }   func Mul(a, b int) int {     log.Infof(\"Mul(%v, %v)\", a, b)     return a + b \/\/ \u0442\u0443\u0442 \u043e\u0448\u0438\u0431\u043a\u0430 }<\/code><\/pre>\n<p>\u0418 \u0442\u0435\u0441\u0442\u044b \u043a \u044d\u0442\u043e\u043c\u0443 \u043a\u043e\u0434\u0443:  <\/p>\n<pre><code class=\"go\">package yourpackage   import \"testing\"   func TestPlus(t *testing.T) {     a, b, expected := 3, 2, 5     got := Plus(a, b)     if got != expected {    \t t.Errorf(\"Plus(%v, %v) return %v; want %v\", a, b, got, expected)     } }   func TestMinus(t *testing.T) {     a, b, expected := 3, 2, 1     got := Minus(a, b)     if got != expected {    \t t.Errorf(\"Minus(%v, %v) return %v; want %v\", a, b, got, expected)     } }   func TestMul(t *testing.T) {     a, b, expected := 3, 2, 6     got := Mul(a, b)     if got != expected {    \t t.Errorf(\"Mul(%v, %v) return %v; want %v\", a, b, got, expected)     } }<\/code><\/pre>\n<p>\u041f\u0440\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0435 \u0442\u0435\u0441\u0442\u043e\u0432 \u043c\u044b \u0432\u0438\u0434\u0438\u043c, \u043f\u043e\u043c\u0438\u043c\u043e \u043e\u0448\u0438\u0431\u043a\u0438, \u0435\u0449\u0451 \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043e\u0442 \u0434\u0440\u0443\u0433\u0438\u0445 \u0442\u0435\u0441\u0442\u043e\u0432:  <\/p>\n<pre><code class=\"go\">time=\"2021-03-22T22:09:54+03:00\" level=info msg=\"Plus(3, 2)\" time=\"2021-03-22T22:09:54+03:00\" level=info msg=\"Minus(3, 2)\" time=\"2021-03-22T22:09:54+03:00\" level=info msg=\"Mul(3, 2)\" --- FAIL: TestMul (0.00s) \tyourpackage_test.go:55: Mul(3, 2) return 5; want 6 FAIL FAIL\tgotest2\/yourpackage \t0.002s FAIL<\/code><\/pre>\n<p>\u0415\u0441\u043b\u0438 \u043a\u043e\u0434\u043e\u0432\u0430\u044f \u0431\u0430\u0437\u0430 \u0431\u043e\u043b\u044c\u0448\u0430\u044f, \u0442\u043e \u0443\u043f\u0430\u0432\u0448\u0438\u0435 \u0442\u0435\u0441\u0442\u044b \u043f\u043e\u0442\u0435\u0440\u044f\u044e\u0442\u0441\u044f \u0441\u0440\u0435\u0434\u0438 \u043b\u0438\u0448\u043d\u0435\u0433\u043e \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f. \u0427\u0442\u043e\u0431\u044b \u0442\u0430\u043a\u043e\u0433\u043e \u043d\u0435 \u0431\u044b\u043b\u043e, \u043c\u043e\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043f\u0435\u0440\u0435\u0445\u0432\u0430\u0442 \u043b\u043e\u0433\u043e\u0432 \u0432 \u0442\u0435\u0441\u0442\u0430\u0445. \u0414\u043b\u044f \u043f\u0440\u0438\u0432\u0435\u0434\u0451\u043d\u043d\u043e\u0433\u043e \u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u044d\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0432\u043e\u0442 \u0442\u0430\u043a:<\/p>\n<pre><code class=\"go\">package yourpackage   import (     \"io\"     \"testing\"       \"github.com\/sirupsen\/logrus\" )   type logCapturer struct {     *testing.T     origOut io.Writer }   func (tl logCapturer) Write(p []byte) (n int, err error) {     tl.Logf((string)(p))     return len(p), nil }   func (tl logCapturer) Release() {     logrus.SetOutput(tl.origOut) }   func CaptureLog(t *testing.T) *logCapturer {     lc := logCapturer{T: t, origOut: logrus.StandardLogger().Out}     if !testing.Verbose() {    \t logrus.SetOutput(lc)     }     return &amp;lc }   func TestPlus(t *testing.T) {     defer CaptureLog(t).Release()     a, b, expected := 3, 2, 5     got := Plus(a, b)     if got != expected {    \t t.Errorf(\"Plus(%v, %v) return %v; want %v\", a, b, got, expected)     } }   func TestMinus(t *testing.T) {     defer CaptureLog(t).Release()     a, b, expected := 3, 2, 5     got := Minus(a, b)     if got != expected {    \t t.Errorf(\"Minus(%v, %v) return %v; want %v\", a, b, got, expected)     } }   func TestMul(t *testing.T) {     defer CaptureLog(t).Release()     a, b, expected := 3, 2, 5     got := Mul(a, b)     if got != expected {    \t t.Errorf(\"Mul(%v, %v) return %v; want %v\", a, b, got, expected)     } }<\/code><\/pre>\n<p>\u0418 \u0442\u043e\u0433\u0434\u0430 \u0432\u044b\u0432\u043e\u0434 \u0442\u0435\u0441\u0442\u043e\u0432 \u0431\u0443\u0434\u0435\u0442 \u043b\u0430\u043a\u043e\u043d\u0438\u0447\u043d\u0435\u0435, \u0438 \u0441\u0440\u0430\u0437\u0443 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043d\u044f\u0442\u043d\u043e, \u043a\u0430\u043a\u043e\u0435 \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0438 \u0432 \u043a\u0430\u043a\u043e\u043c \u0442\u0435\u0441\u0442\u0435 \u0432\u0435\u043b\u043e\u0441\u044c:<\/p>\n<pre><code class=\"go\">--- FAIL: TestMul (0.00s) \tyourpackage_test.go:16: time=\"2021-03-22T22:10:52+03:00\" level=info msg=\"Mul(3, 2)\" \tyourpackage_test.go:55: Mul(3, 2) return 5; want 6 FAIL FAIL\tgotest2\/yourpackage \t0.002s FAIL<\/code><\/pre>\n<p>\u0417\u0434\u0435\u0441\u044c \u043f\u0440\u0438\u0432\u0435\u0434\u0451\u043d \u043f\u0440\u0438\u043c\u0435\u0440 \u0434\u043b\u044f Logrus, \u043d\u043e \u043d\u0435\u0447\u0442\u043e \u043f\u043e\u0445\u043e\u0436\u0435\u0435 \u043c\u043e\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0441 \u043b\u044e\u0431\u043e\u0439 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u043e\u0439 \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0434\u043b\u044f \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 Zap \u0435\u0441\u0442\u044c <a href=\"https:\/\/pkg.go.dev\/go.uber.org\/zap\/zaptest#NewLogger\"><u>\u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u043c\u043e\u0434\u0443\u043b\u044c<\/u><\/a>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u0431\u043b\u0435\u0433\u0447\u0430\u0435\u0442 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435.<\/p>\n<h3>\u0421\u0447\u0438\u0442\u0430\u0435\u043c \u043f\u043e\u043a\u0440\u044b\u0442\u0438\u0435 \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e<\/h3>\n<p>\u0412 Go \u0432\u0441\u0435\u0433\u0434\u0430 \u0431\u044b\u043b\u0430 \u043a\u0430\u043a\u0430\u044f-\u0442\u043e \u0441\u0442\u0440\u0430\u043d\u043d\u043e\u0441\u0442\u044c \u0441 \u043f\u043e\u0434\u0441\u0447\u0451\u0442\u043e\u043c \u043f\u043e\u043a\u0440\u044b\u0442\u0438\u044f \u043a\u043e\u0434\u0430 \u0442\u0435\u0441\u0442\u0430\u043c\u0438. \u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u043d\u0435\u043b\u044c\u0437\u044f \u0431\u044b\u043b\u043e \u043f\u043e\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u043e\u0442\u0447\u0451\u0442 \u043f\u043e \u043f\u043e\u043a\u0440\u044b\u0442\u0438\u044e \u0434\u043b\u044f \u0432\u0441\u0435\u0445 \u043f\u0430\u043a\u0435\u0442\u043e\u0432, \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u0445 \u0432 \u0440\u0430\u043c\u043a\u0430\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u0414\u043e \u0441\u0438\u0445 \u043f\u043e\u0440 \u0432 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f\u0445 \u043c\u043e\u0436\u043d\u043e \u0432\u0441\u0442\u0440\u0435\u0442\u0438\u0442\u044c \u0441\u043a\u0440\u0438\u043f\u0442\u044b, \u043f\u043e\u0445\u043e\u0436\u0438\u0435 \u043d\u0430 <a href=\"https:\/\/gist.github.com\/cdennison\/cba009cf297aa2a92759278b5c578ae4\"><u>\u044d\u0442\u043e\u0442<\/u><\/a>, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u0434\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0442\u0435\u0441\u0442\u043e\u0432 \u043f\u043e \u0432\u0441\u0435\u043c \u043f\u0430\u043a\u0435\u0442\u0430\u043c \u0438 \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043e \u043f\u043e\u043a\u0440\u044b\u0442\u0438\u0438 \u0432 \u043e\u0434\u0438\u043d \u043e\u0442\u0447\u0451\u0442. \u0421\u0435\u0439\u0447\u0430\u0441 \u0441 \u044d\u0442\u0438\u043c \u0432\u0441\u0451 \u0445\u043e\u0440\u043e\u0448\u043e, \u043d\u043e \u0435\u0441\u0442\u044c \u043d\u0435\u043e\u0447\u0435\u0432\u0438\u0434\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442.&nbsp;<\/p>\n<p>\u0414\u043e\u043f\u0443\u0441\u0442\u0438\u043c, \u043d\u0430\u0448 \u043f\u0440\u043e\u0435\u043a\u0442 \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0438\u0437 \u0442\u0440\u0451\u0445 \u043f\u0430\u043a\u0435\u0442\u043e\u0432. \u0418 \u043c\u044b \u0445\u043e\u0442\u0438\u043c \u0434\u043b\u044f \u043d\u0438\u0445 \u043f\u043e\u0441\u0447\u0438\u0442\u0430\u0442\u044c \u043f\u043e\u043a\u0440\u044b\u0442\u0438\u0435. \u041e\u0431\u0440\u0430\u0449\u0430\u0435\u043c\u0441\u044f \u0437\u0430 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043a \u0443\u0442\u0438\u043b\u0438\u0442\u0435 cover, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0441\u043a\u0430\u0436\u0435\u0442 \u043d\u0430\u043c \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0435:<\/p>\n<pre><code class=\"go\">$ go tool cover -help Usage of 'go tool cover': Given a coverage profile produced by 'go test':     \tgo test -coverprofile=c.out ... Display coverage percentages to stdout for each function:     \tgo tool cover -func=c.out<\/code><\/pre>\n<p>\u041f\u0440\u043e\u0431\u0443\u0435\u043c:  <\/p>\n<pre><code class=\"go\">$ go test -coverprofile=c.out .\/... ok  \tgotestcover\/minus   \t0.001s  coverage: 100.0% of statements ?   \tgotestcover\/mul [no test files] ok  \tgotestcover\/plus    \t0.001s  coverage: 100.0% of statements<\/code><\/pre>\n<p>\u0423\u0436\u0435 \u0438\u0437 \u044d\u0442\u043e\u0433\u043e \u0432\u044b\u0432\u043e\u0434\u0430 \u0432\u0438\u0434\u043d\u043e, \u0447\u0442\u043e \u0443 \u043d\u0430\u0441 \u0434\u0432\u0430 \u043f\u0430\u043a\u0435\u0442\u0430 \u043f\u043e\u043a\u0440\u044b\u0442\u044b \u043d\u0430 100 % \u0438 \u0434\u043b\u044f \u043e\u0434\u043d\u043e\u0433\u043e \u043f\u0430\u043a\u0435\u0442\u0430 \u043d\u0435\u0442 \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0445 \u0444\u0430\u0439\u043b\u043e\u0432. \u041f\u043e\u043b\u0443\u0447\u0438\u043c \u043e\u0442\u0447\u0451\u0442 \u043e \u043f\u043e\u043a\u0440\u044b\u0442\u0438\u0438:<\/p>\n<pre><code class=\"go\">$ go tool cover -func=c.out gotestcover\/minus\/minus.go:4:   Minus       \t100.0% gotestcover\/plus\/plus.go:4: \tPlus        \t100.0% total:                      \t(statements)\t100.0%<\/code><\/pre>\n<p>\u041d\u043e \u0442\u0443\u0442 \u0447\u0442\u043e-\u0442\u043e \u043d\u0435 \u0442\u0430\u043a. \u0412 \u043e\u0442\u0447\u0451\u0442\u0435 \u0433\u043e\u0432\u043e\u0440\u0438\u0442\u0441\u044f \u043e \u043f\u043e\u043b\u043d\u043e\u043c \u043f\u043e\u043a\u0440\u044b\u0442\u0438\u0438 \u0442\u0435\u0441\u0442\u0430\u043c\u0438. \u0425\u043e\u0442\u044f \u043c\u044b \u0437\u043d\u0430\u0435\u043c, \u0447\u0442\u043e \u044d\u0442\u043e \u043d\u0435 \u0442\u0430\u043a. \u042d\u0442\u043e \u0432\u0441\u0451 \u043f\u043e\u0442\u043e\u043c\u0443, \u0447\u0442\u043e \u043f\u0440\u0438 \u043f\u043e\u0434\u0441\u0447\u0451\u0442\u0435 \u043f\u043e\u043a\u0440\u044b\u0442\u0438\u044f \u043d\u0435 \u0443\u0447\u0438\u0442\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043f\u0430\u043a\u0435\u0442, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043d\u0435\u0442 \u0442\u0435\u0441\u0442\u043e\u0432. \u0415\u0433\u043e \u043d\u0435 \u0431\u0443\u0434\u0435\u0442 \u0438 \u0432 HTML-\u043e\u0442\u0447\u0451\u0442\u0435. \u0418 \u043a\u0430\u0436\u0435\u0442\u0441\u044f, \u0447\u0442\u043e \u044d\u0442\u043e \u043d\u0435 \u0432\u0441\u0435\u0433\u0434\u0430 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u044b\u043c, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u0437\u0430\u0447\u0430\u0441\u0442\u0443\u044e \u043c\u044b \u0445\u043e\u0442\u0438\u043c \u0437\u043d\u0430\u0442\u044c \u043f\u043e\u043a\u0440\u044b\u0442\u0438\u0435 \u0432\u0441\u0435\u0433\u043e \u043a\u043e\u0434\u0430, \u0430 \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0442\u043e\u0433\u043e, \u0434\u043b\u044f \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u043c\u044b \u043d\u0430\u043f\u0438\u0441\u0430\u043b\u0438 \u0442\u0435\u0441\u0442\u044b. \u042d\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u0440\u0430\u0432\u0438\u0442\u044c, \u0443\u043a\u0430\u0437\u0430\u0432 \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0439 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 \u043f\u0440\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0435 \u0442\u0435\u0441\u0442\u043e\u0432:<\/p>\n<pre><code class=\"go\">go test -coverpkg=.\/... -coverprofile=c.out .\/\u2026<\/code><\/pre>\n<p>\u0418 \u0442\u0435\u043f\u0435\u0440\u044c \u043e\u0442\u0447\u0451\u0442 \u0432\u044b\u0434\u0430\u0451\u0442 \u043e\u0436\u0438\u0434\u0430\u0435\u043c\u044b\u0439 \u043f\u0440\u043e\u0446\u0435\u043d\u0442 \u043f\u043e\u043a\u0440\u044b\u0442\u0438\u044f \u0442\u0435\u0441\u0442\u0430\u043c\u0438:<\/p>\n<pre><code class=\"go\">$ go tool cover -func=c.out gotestcover\/minus\/minus.go:4:   Minus       \t100.0% gotestcover\/mul\/mul.go:4:   \tMul         \t0.0% gotestcover\/plus\/plus.go:4: \tPlus        \t100.0% total:                      \t(statements)\t66.7%<\/code><\/pre>\n<h3>\u0421\u0447\u0438\u0442\u0430\u0435\u043c \u043f\u043e\u043a\u0440\u044b\u0442\u0438\u0435 \u043f\u0440\u0438 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043a\u0430\u043a \u0447\u0435\u0440\u043d\u043e\u0433\u043e \u044f\u0449\u0438\u043a\u0430<\/h3>\n<p>\u041f\u0438\u0441\u0430\u0442\u044c \u0442\u0435\u0441\u0442\u044b \u043d\u0430 Go \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e-\u0442\u0430\u043a\u0438 \u0441\u043b\u043e\u0436\u043d\u043e. \u0418 \u0435\u0441\u043b\u0438 \u0432\u044b \u0440\u0430\u0437\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442\u0435 \u043a\u0430\u043a\u043e\u0439-\u043d\u0438\u0431\u0443\u0434\u044c \u0432\u0435\u0431-\u0441\u0435\u0440\u0432\u0438\u0441, \u0442\u043e \u0438\u043d\u043e\u0433\u0434\u0430 \u0431\u044b\u0432\u0430\u0435\u0442 \u043f\u0440\u043e\u0449\u0435 \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0442\u0435\u0441\u0442\u044b \u043d\u0430 \u0434\u0440\u0443\u0433\u043e\u043c \u044f\u0437\u044b\u043a\u0435, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043d\u0430 Python, \u0438 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043a\u0430\u043a \u00ab\u0447\u0451\u0440\u043d\u044b\u0439 \u044f\u0449\u0438\u043a\u00bb.&nbsp;<\/p>\n<p>\u041d\u043e \u0432\u043e\u0437\u043d\u0438\u043a\u0430\u0435\u0442 \u0432\u043e\u043f\u0440\u043e\u0441, \u0430 \u043c\u043e\u0436\u043d\u043e \u043b\u0438 \u043f\u043e\u0441\u0447\u0438\u0442\u0430\u0442\u044c \u043f\u043e\u043a\u0440\u044b\u0442\u0438\u0435 \u0434\u043b\u044f \u0442\u0430\u043a\u043e\u0433\u043e \u0441\u043f\u043e\u0441\u043e\u0431\u0430<\/p>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-321975","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/321975","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=321975"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/321975\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=321975"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=321975"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=321975"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}