{"id":634,"date":"2019-12-01T11:36:30","date_gmt":"2019-12-01T19:36:30","guid":{"rendered":"http:\/\/modulesafari.com\/?p=634"},"modified":"2019-12-02T18:04:22","modified_gmt":"2019-12-03T02:04:22","slug":"testify-test-your-go-code","status":"publish","type":"post","link":"http:\/\/modulesafari.com\/testify-test-your-go-code\/","title":{"rendered":"Testify; Test Your Go Code"},"content":{"rendered":"\n

Testify is a testing library that makes writing tests for your Go code easy. It reduces the amount of code you need for tests, while also providing extra functionality for easy mocking. Especially when combined with mockery, you really have a Golang testing powerhouse. Here is a direct link<\/a> to the Github repository if you are interested.<\/p>\n\n\n\n

Assert<\/h2>\n\n\n\n

Testify’s assert package contains functions that make checking certain conditions easy. They replace the normal if statement list flow and have reflection built-in for comparisons between structs. For this example, let’s say we are making a function fib, which calculates the number in the nth place in the Fibonacci Sequence. Here is our naive implementation of this, which has a few issues.<\/p>\n\n\n\n

func fib(n int64) int64 {\n\tvar a int64 = 0\n\tvar b int64 = 1\n\tfor i := int64(0); i < n-1; i++ {\n\t\ttmp := b\n\t\tb = a + b\n\t\ta = tmp\n\t}\n\treturn b\n}<\/pre>\n\n\n\n

We want to be sure that this implementation is correct, so we add some tests for it using testify. <\/p>\n\n\n\n

package main\n\nimport(\n\t\"testing\"\n\n\t\"github.com\/stretchr\/testify\/assert\"\n)\n\nfunc TestFib(t *testing.T) {\n\tassert.Equal(t, int64(0), fib(0))\n\tassert.Equal(t, int64(1), fib(1))\n\tassert.Equal(t, int64(1), fib(2))\n\tassert.Equal(t, int64(6765), fib(20))\n}<\/pre>\n\n\n\n

Now, we run our tests with go test<\/code> and we can immediately see an issue.<\/p>\n\n\n\n

--- FAIL: TestFib (0.00s)\n    fib_test.go:12: \n        \tError Trace:\tfib_test.go:10\n        \tError:      \tNot equal: \n        \t            \texpected: 0\n        \t            \tactual  : 1\n        \tTest:       \tTestFib\nFAIL<\/pre>\n\n\n\n

Thanks to testify, we easily see that on line 10, the output of the function was 1, instead of 0. We go to our code and see that we don’t handle the case of n == 0, and fix the issue. <\/p>\n\n\n\n

func fib(n int64) int64 {\n\tvar a int64 = 0\n\tvar b int64 = 1\n\tfor i := int64(0); i < n; i++ {\n\t\ttmp := b\n\t\tb = a + b\n\t\ta = tmp\n\t}\n\treturn a\n}<\/pre>\n\n\n\n

The tests passed, and we can be more confident that our code is correct. <\/p>\n\n\n\n

Require<\/h2>\n\n\n\n

While assert is great for most cases, sometimes you have dependencies in your test function. There, you want to make sure that when a test fails, it reports only what failed. Enter the require package. Require feels like a carbon copy of the assert package, with just one key difference: it calls t.FailNow()<\/code>. Let’s make a function which uses the Fibonacci function from earlier, and outputs all terms up to n in an array. <\/p>\n\n\n\n

func fibAll(n int64) []int64 {\n\tif n > 0 {\n\t\treturn nil\n\t}\n\tout := make([]int64, n + 1)\n\tfor i := int64(0); i <= n; i++ {\n\t\tout[i] = fib(i)\n\t}\n\treturn out\n}<\/pre>\n\n\n\n

This function needs some tests, so let’s write some up real quick. We want to do some spot checking to make sure that the sequence is generated correctly. <\/p>\n\n\n\n

func TestFibAll(t *testing.T) {\n\tfor i := int64(15); i < 40; i++ {\n\t\tfibNumbers := fibAll(i)\n\t\tassert.NotNil(t, fibNumbers)\n\t\tassert.Len(t, fibNumbers, int(i+1))\n\t\tassert.Equal(t, 233, fibNumbers[13])\n\t\tassert.Equal(t, 55, fibNumbers[10])\n\t}\n}<\/pre>\n\n\n\n

We run our tests and get back this messy error.<\/p>\n\n\n\n

--- FAIL: TestFibAll (0.00s)\n    fib_test.go:19: \n        \tError Trace:\tfib_test.go:19\n        \tError:      \tExpected value not to be nil.\n        \tTest:       \tTestFibAll\n    fib_test.go:20: \n        \tError Trace:\tfib_test.go:20\n        \tError:      \t\"[]\" should have 16 item(s), but has 0\n        \tTest:       \tTestFibAll\npanic: runtime error: index out of range [13] with length 0 [recovered]\n\tpanic: runtime error: index out of range [13] with length 0\n\ngoroutine 21 [running]:\ntesting.tRunner.func1(0xc000116200)\n\t\/snap\/go\/4762\/src\/testing\/testing.go:874 +0x3a3\npanic(0x719700, 0xc0000d42a0)\n[Full stack trace omitted]\nexit status 2\nFAIL\n<\/pre>\n\n\n\n

As you can see, the tests reported 2 failures instead of just one, and the code panicked. Of course, this is still usable and would be significantly better than nothing. However, if the unit tests were more complex, it can start to become unclear as to what the actual problem is. So, let’s put “require” to use.<\/p>\n\n\n\n

func TestFibAll(t *testing.T) {\n\tfor i := int64(15); i < 40; i++ {\n\t\tfibNumbers := fibAll(i)\n\t\trequire.NotNil(t, fibNumbers)\n\t\trequire.Len(t, fibNumbers, int(i+1))\n\t\tassert.Equal(t, 233, fibNumbers[13])\n\t\tassert.Equal(t, 55, fibNumbers[10])\n\t}\n}<\/pre>\n\n\n\n

When we run our tests, it becomes very clear what the issue is. <\/p>\n\n\n\n

--- FAIL: TestFibAll (0.00s)\n    fib_test.go:20: \n        \tError Trace:\tfib_test.go:20\n        \tError:      \tExpected value not to be nil.\n        \tTest:       \tTestFibAll\nFAIL<\/pre>\n\n\n\n

This is a significant improvement. Especially as the complexity of a codebase increases, simplified test failures can save you a lot of time. The last thing anyone wants to do is dig through a ton of logs and code, just to find that the issue is an inverted comparison. <\/p>\n\n\n\n

Overall, Testify is a great library for reducing the complexity of your Go test code. Every time I have used it, I have been extremely satisfied, as the functions do exactly what they say. I strongly suggest checking out the mock package and its use with mockery<\/a><\/p>\n\n\n\n

<\/p>\n","protected":false},"excerpt":{"rendered":"

Testify is a testing library that makes writing tests for your Go code easy. It reduces the amount of code you need for tests, while also providing extra functionality for easy mocking. Especially when combined with mockery, you really have a Golang testing powerhouse. Here is a direct link to the Github repository if you […]<\/p>\n","protected":false},"author":1,"featured_media":636,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_et_pb_use_builder":"off","_et_pb_old_content":"\n

Testify is a testing library that makes writing tests for your Go code easy. It reduces the amount of code you need for tests, while also providing extra functionality for easy mocking. Especially when combined with mockery, you really have a Golang testing powerhouse. Here is a direct link<\/a> to the Github repository if you are interested.<\/p>\n\n\n\n

Assert<\/h2>\n\n\n\n

Testify's assert package contains functions that make checking certain conditions easy. They replace the normal if statement list flow and have reflection built-in for comparisons between structs. For this example, let's say we are making a function fib, which calculates the number in the nth place in the Fibonacci Sequence. Here is our naive implementation of this, which has a few issues.<\/p>\n\n\n\n

func fib(n int64) int64 {\n\tvar a int64 = 0\n\tvar b int64 = 1\n\tfor i := int64(0); i < n-1; i++ {\n\t\ttmp := b\n\t\tb = a + b\n\t\ta = tmp\n\t}\n\treturn b\n}<\/pre>\n\n\n\n

We want to be sure that this implementation is correct, so we add some tests for it using testify. <\/p>\n\n\n\n

package main\n\nimport(\n\t\"testing\"\n\n\t\"github.com\/stretchr\/testify\/assert\"\n)\n\nfunc TestFib(t *testing.T) {\n\tassert.Equal(t, int64(0), fib(0))\n\tassert.Equal(t, int64(1), fib(1))\n\tassert.Equal(t, int64(1), fib(2))\n\tassert.Equal(t, int64(6765), fib(20))\n}<\/pre>\n\n\n\n

Now, we run our tests with go test<\/code> and we can immediately see an issue.<\/p>\n\n\n\n

--- FAIL: TestFib (0.00s)\n    fib_test.go:12: \n        \tError Trace:\tfib_test.go:10\n        \tError:      \tNot equal: \n        \t            \texpected: 0\n        \t            \tactual  : 1\n        \tTest:       \tTestFib\nFAIL<\/pre>\n\n\n\n

Thanks to testify, we easily see that on line 10, the output of the function was 1, instead of 0. We go to our code and see that we don't handle the case of n == 0, and fix the issue. <\/p>\n\n\n\n

func fib(n int64) int64 {\n\tvar a int64 = 0\n\tvar b int64 = 1\n\tfor i := int64(0); i < n; i++ {\n\t\ttmp := b\n\t\tb = a + b\n\t\ta = tmp\n\t}\n\treturn a\n}<\/pre>\n\n\n\n

The tests passed, and we can be more confident that our code is correct. <\/p>\n\n\n\n

Require<\/h2>\n\n\n\n

While assert is great for most cases, sometimes you have dependencies in your test function. There, you want to make sure that when a test fails, it reports only what failed. Enter the require package. Require feels like a carbon copy of the assert package, with just one key difference: it calls t.FailNow()<\/code>. Let's make a function which uses the Fibonacci function from earlier, and outputs all terms up to n in an array. <\/p>\n\n\n\n

func fibAll(n int64) []int64 {\n\tif n > 0 {\n\t\treturn nil\n\t}\n\tout := make([]int64, n + 1)\n\tfor i := int64(0); i <= n; i++ {\n\t\tout[i] = fib(i)\n\t}\n\treturn out\n}<\/pre>\n\n\n\n

This function needs some tests, so let's write some up real quick. We want to do some spot checking to make sure that the sequence is generated correctly. <\/p>\n\n\n\n

func TestFibAll(t *testing.T) {\n\tfor i := int64(15); i < 40; i++ {\n\t\tfibNumbers := fibAll(i)\n\t\tassert.NotNil(t, fibNumbers)\n\t\tassert.Len(t, fibNumbers, int(i+1))\n\t\tassert.Equal(t, 233, fibNumbers[13])\n\t\tassert.Equal(t, 55, fibNumbers[10])\n\t}\n}<\/pre>\n\n\n\n

We run our tests and get back this messy error.<\/p>\n\n\n\n

--- FAIL: TestFibAll (0.00s)\n    fib_test.go:19: \n        \tError Trace:\tfib_test.go:19\n        \tError:      \tExpected value not to be nil.\n        \tTest:       \tTestFibAll\n    fib_test.go:20: \n        \tError Trace:\tfib_test.go:20\n        \tError:      \t\"[]\" should have 16 item(s), but has 0\n        \tTest:       \tTestFibAll\npanic: runtime error: index out of range [13] with length 0 [recovered]\n\tpanic: runtime error: index out of range [13] with length 0\n\ngoroutine 21 [running]:\ntesting.tRunner.func1(0xc000116200)\n\t\/snap\/go\/4762\/src\/testing\/testing.go:874 +0x3a3\npanic(0x719700, 0xc0000d42a0)\n[Full stack trace omitted]\nexit status 2\nFAIL\n<\/pre>\n\n\n\n

As you can see, the tests reported 2 failures instead of just one, and the code panicked. Of course, this is still usable and would be significantly better than nothing. However, if the unit tests were more complex, it can start to become unclear as to what the actual problem is. So, let's put \"require\" to use.<\/p>\n\n\n\n

func TestFibAll(t *testing.T) {\n\tfor i := int64(15); i < 40; i++ {\n\t\tfibNumbers := fibAll(i)\n\t\trequire.NotNil(t, fibNumbers)\n\t\trequire.Len(t, fibNumbers, int(i+1))\n\t\tassert.Equal(t, 233, fibNumbers[13])\n\t\tassert.Equal(t, 55, fibNumbers[10])\n\t}\n}<\/pre>\n\n\n\n

When we run our tests, it becomes very clear what the issue is. <\/p>\n\n\n\n

--- FAIL: TestFibAll (0.00s)\n    fib_test.go:20: \n        \tError Trace:\tfib_test.go:20\n        \tError:      \tExpected value not to be nil.\n        \tTest:       \tTestFibAll\nFAIL<\/pre>\n\n\n\n

This is a significant improvement. Especially as the complexity of a codebase increases, simplified test failures can save you a lot of time. The last thing anyone wants to do is dig through a ton of logs and code, just to find that the issue is an inverted comparison. <\/p>\n\n\n\n

Overall, Testify is a great library for reducing the complexity of your Go test code. Every time I have used it, I have been extremely satisfied, as the functions do exactly what they say. There is also the mock package in this library, however, I am going to talk about that when I cover mockery, as they complement each of extremely well. <\/p>\n\n\n\n

<\/p>\n","_et_gb_content_width":""},"categories":[6],"tags":[9,231,232],"yst_prominent_words":[244,248,252,138,250,240,257,241,189,256,193,247,254,255,225,253,246,234,233,236],"yoast_head":"\nTestify; Test Your Go Code - Module Safari<\/title>\n<meta name=\"description\" content=\"Testify is a testing library to make testing your Go code easy. It reduces the amount of code you need to write for tests\" \/>\n<meta name=\"robots\" content=\"index, follow\" \/>\n<meta name=\"googlebot\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<meta name=\"bingbot\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"http:\/\/modulesafari.com\/testify-test-your-go-code\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Testify; Test Your Go Code - Module Safari\" \/>\n<meta property=\"og:description\" content=\"Testify is a testing library to make testing your Go code easy. It reduces the amount of code you need to write for tests\" \/>\n<meta property=\"og:url\" content=\"http:\/\/modulesafari.com\/testify-test-your-go-code\/\" \/>\n<meta property=\"og:site_name\" content=\"Module Safari\" \/>\n<meta property=\"article:published_time\" content=\"2019-12-01T19:36:30+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2019-12-03T02:04:22+00:00\" \/>\n<meta property=\"og:image\" content=\"http:\/\/modulesafari.com\/wp-content\/uploads\/2019\/12\/bug-finding.png\" \/>\n\t<meta property=\"og:image:width\" content=\"960\" \/>\n\t<meta property=\"og:image:height\" content=\"672\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Organization\",\"@id\":\"http:\/\/modulesafari.com\/#organization\",\"name\":\"Module Safari\",\"url\":\"http:\/\/modulesafari.com\/\",\"sameAs\":[],\"logo\":{\"@type\":\"ImageObject\",\"@id\":\"http:\/\/modulesafari.com\/#logo\",\"inLanguage\":\"en-US\",\"url\":\"http:\/\/modulesafari.com\/wp-content\/uploads\/2019\/11\/PNG-Logo-02-not-transparent.png\",\"width\":2026,\"height\":530,\"caption\":\"Module Safari\"},\"image\":{\"@id\":\"http:\/\/modulesafari.com\/#logo\"}},{\"@type\":\"WebSite\",\"@id\":\"http:\/\/modulesafari.com\/#website\",\"url\":\"http:\/\/modulesafari.com\/\",\"name\":\"Module Safari\",\"description\":\"development simplified\",\"publisher\":{\"@id\":\"http:\/\/modulesafari.com\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":\"http:\/\/modulesafari.com\/?s={search_term_string}\",\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"en-US\"},{\"@type\":\"ImageObject\",\"@id\":\"http:\/\/modulesafari.com\/testify-test-your-go-code\/#primaryimage\",\"inLanguage\":\"en-US\",\"url\":\"http:\/\/modulesafari.com\/wp-content\/uploads\/2019\/12\/bug-finding.png\",\"width\":960,\"height\":672},{\"@type\":\"WebPage\",\"@id\":\"http:\/\/modulesafari.com\/testify-test-your-go-code\/#webpage\",\"url\":\"http:\/\/modulesafari.com\/testify-test-your-go-code\/\",\"name\":\"Testify; Test Your Go Code - Module Safari\",\"isPartOf\":{\"@id\":\"http:\/\/modulesafari.com\/#website\"},\"primaryImageOfPage\":{\"@id\":\"http:\/\/modulesafari.com\/testify-test-your-go-code\/#primaryimage\"},\"datePublished\":\"2019-12-01T19:36:30+00:00\",\"dateModified\":\"2019-12-03T02:04:22+00:00\",\"description\":\"Testify is a testing library to make testing your Go code easy. It reduces the amount of code you need to write for tests\",\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"http:\/\/modulesafari.com\/testify-test-your-go-code\/\"]}]},{\"@type\":\"Article\",\"@id\":\"http:\/\/modulesafari.com\/testify-test-your-go-code\/#article\",\"isPartOf\":{\"@id\":\"http:\/\/modulesafari.com\/testify-test-your-go-code\/#webpage\"},\"author\":{\"@id\":\"http:\/\/modulesafari.com\/#\/schema\/person\/a31876f85a9f031cf62afd4e79f746aa\"},\"headline\":\"Testify; Test Your Go Code\",\"datePublished\":\"2019-12-01T19:36:30+00:00\",\"dateModified\":\"2019-12-03T02:04:22+00:00\",\"commentCount\":0,\"mainEntityOfPage\":{\"@id\":\"http:\/\/modulesafari.com\/testify-test-your-go-code\/#webpage\"},\"publisher\":{\"@id\":\"http:\/\/modulesafari.com\/#organization\"},\"image\":{\"@id\":\"http:\/\/modulesafari.com\/testify-test-your-go-code\/#primaryimage\"},\"keywords\":\"golang,test,testing\",\"articleSection\":\"Golang\",\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"http:\/\/modulesafari.com\/testify-test-your-go-code\/#respond\"]}]},{\"@type\":[\"Person\"],\"@id\":\"http:\/\/modulesafari.com\/#\/schema\/person\/a31876f85a9f031cf62afd4e79f746aa\",\"name\":\"Nathaniel Blakely\",\"image\":{\"@type\":\"ImageObject\",\"@id\":\"http:\/\/modulesafari.com\/#personlogo\",\"inLanguage\":\"en-US\",\"url\":\"http:\/\/1.gravatar.com\/avatar\/1d85a4c5bf257b6a8972ab9bbaee0b51?s=96&d=mm&r=g\",\"caption\":\"Nathaniel Blakely\"}}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","_links":{"self":[{"href":"http:\/\/modulesafari.com\/wp-json\/wp\/v2\/posts\/634"}],"collection":[{"href":"http:\/\/modulesafari.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/modulesafari.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/modulesafari.com\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/modulesafari.com\/wp-json\/wp\/v2\/comments?post=634"}],"version-history":[{"count":22,"href":"http:\/\/modulesafari.com\/wp-json\/wp\/v2\/posts\/634\/revisions"}],"predecessor-version":[{"id":688,"href":"http:\/\/modulesafari.com\/wp-json\/wp\/v2\/posts\/634\/revisions\/688"}],"wp:featuredmedia":[{"embeddable":true,"href":"http:\/\/modulesafari.com\/wp-json\/wp\/v2\/media\/636"}],"wp:attachment":[{"href":"http:\/\/modulesafari.com\/wp-json\/wp\/v2\/media?parent=634"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/modulesafari.com\/wp-json\/wp\/v2\/categories?post=634"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/modulesafari.com\/wp-json\/wp\/v2\/tags?post=634"},{"taxonomy":"yst_prominent_words","embeddable":true,"href":"http:\/\/modulesafari.com\/wp-json\/wp\/v2\/yst_prominent_words?post=634"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}