richard mille replica
Together these kind of watches are called your "Dirty Dozen" by simply army view enthusiasts and amassing among just about richard mille replica all 14 is difficult as a few have been merely manufactured in modest numbers.
Optis | Our Blog

Writing tests for some code you have written. We all have done it, but who has done it in GoLang? You might have used some AWS Lambda functions or tried out writing go code. But keeping that code stable, maintainable, and bug-free, while you are developing it, that is where testing comes in.

If you are reading this post I hope you have some basic go knowledge, if you do not, see the following links. They will help you with getting started in the go language:

Alright, let’s get to the good stuff.

Where to put your tests

In Golang it is quite easy, your test files are right next to your actual code files. So if you want to run some tests on code that is in the bar.go file, you create a test file bar_test.go in that same directory. Note the ‘_test’ suffix for the file. This is a required naming pattern in go.

What’s in a test file

Now that we know where to put a test file, it is time to take a look at what you have to put in it.

Here is a simple go program and a test for a function in it:

main.go:

package main

import "fmt"

func main() {
   list := []int{1, 2, 3, 3, 8, 4, 5}

   lastIndexOfFive := LastIndex(list, 5)
   fmt.Printf("the last index of %d in the list %v is: %d",
      5, list, lastIndexOfFive)
}

func lastIndex(list []int, x int) int {
   for i := len(list) - 1; i >= 0; i-- {
      if list[i] == x {
         return i
      }
   }
   return -1
}
Github Gist: https://gist.github.com/Coollision/4d9dd0e7f5796f2fba2ac2b49069d80c

the test file: main_test.go

package main

import "testing"

func TestLastIndex(t *testing.T) {
   list := []int{1, 2, 1, 1}
   if got := lastIndex(list, 2); got != 1 {
      t.Errorf("LastIndex(%v, %v) = %v, want %v", list, 2, got, 1)
   }
}
Github Gist: https://gist.github.com/Coollision/6b85d2fed22fbfeab251f8c5c0620aa2

A test file in go starts like any other .go file, with a package declaration. In this example we are using an internal test. This is because we are using the same package name as the package we are testing. This way we also have access to the non-exported function and objects, as you would have within that same package. You can also create a black-box test: you do this by adding a _test suffix to the package name. This might be a strange thing to do at first since there is the 1 package per directory rule In GoLang. And by adding a _test suffix to the package name, we are breaking that rule because that is a new package. But don’t you worry, as with any rule there is an exception to it. And the exception here is with the _test suffix. Since we are using another package to test the code, we no longer have access to the package internals and we are doing a black-box test.

Then we get to the imports, this is the same as in any other go file. Except in tests there will always be the import of the testing package.

Now we are getting to the good stuff, the actual tests. A GoLang test function will always follow the format: func Test<Name>(*testing.T) {}. As you can see, there are 2 requirements. A test function should start with Test as prefix. And should accept a parameter of type *testing.T. As you can see in the example test, we use this parameter to control or test. In the example we call the function t.Errorf to signal test failure.

Running a test (CLI style)

Now you know where to put a test file, and what to put in it, there is still one bit of crucial information missing. And that is how to run a test. Alright, I know you have a fancy IDE that gives you a nice run button to run tests. But let’s take a look at how your fancy IDE actually runs them with the go tool.

It is easy to run all the tests in a package. Make sure you are in the directory of the package you want to test, and then run ‘go test’. This will give the following result:

$ go test
pass
ok       testingfun 0.359s

But this only runs the tests in a specific package, it is more useful to run all tests. This can be done by running the next command: ‘go test ./…’ . This will produce the next result:

$ go test ./... 
ok      testingfun 0.433s
ok      testingfun /foo     0.297s
ok      testingfun /foo/bar 0.161s

But what if I want to run a single test or a specific set of tests? Well the go tool has you covered by adding a ‘-run’ flag you can add a regular expression. This will filter your tests and will only run the tests of which the name matches the regex. An example:

$ go test -run "Index" -v ./...

=== RUN   TestLastIndex
--- PASS: TestLastIndex (0.00s)
PASS
ok      testingfun 0.059s
testing: warning: no tests to run
PASS
ok      testingfun /foo     0.097s [no tests to run]
testing: warning: no tests to run
PASS
ok      testfun/foo/bar 0.350s [no tests to run]

You might have noticed that besides the ‘-run’ flag with argument “Index”. I also added in the -v flag, this will enable verbose logging in your test. This enables more logging in your tests, but it also prints out more information about what tests ran.

The *testing.T package provides

Since we’ve covered the basics for a simple go test, let’s take a closer look at the testing package. The testing package provides us with a lot of functionality. Let’s take a look at the functions it contains:

Errorf(format string, args ...interface{})
Fail()
FailNow()
Failed() bool
Fatal(args ...interface{})
Fatalf(format string, args ...interface{})
Helper()
Log(args ...interface{})
Logf(format string, args ...interface{})
Name() string
Parallel()
Run(name string, f func(t *T)) bool
Skip(args ...interface{})
SkipNow()
Skipf(format string, args ...interface{})
Skipped() bool
Cleanup(func())

I know it looks like a lot at first glance. But think about another language and the number of functions you have specifically for testing, it will probably be more than this. What I won’t do next is go over all these functions and write about what they do, however I will go over some. If you want to get some more information about these functions, read the doc’s on: https://golang.org/pkg/testing/#T

The ‘Error’and ‘Fatal’ functions

They both do the same, fail the current test. But with one key difference, ‘Error won’t end the execution of a test. When you call Error, you are letting go know it can continue the execution of the test. But when you call ‘Fatal’, you are saying that there is no point in continuing execution.

The log functions

When calling ‘t.Log(“write this awesome log”)’ don’t expect to get some log lines in a successful test. These log lines only show up when your test fails or when you run your tests with the verbose (-v) flag.

The Helper function

This is a fun one, if called you are telling the go tool, that the function this is called in, is a helper function. Take for example the next isTrue function:

func isTrue(t *testing.T, b bool) {
   t.Helper()
   if !b {
      t.Fatal()
   }
}
Github Gist: https://gist.github.com/Coollision/7fcfe650513a065ef50010f9830934bc

I suggest you try calling it from inside a test ‘isTrue(t, false)’ . Do this once with and once without the call to t.Helper(). As you might notice, if you omit the call to t.Helper in isTrue. It gets quite hard to find out why the test failed. Because you fail your test with t.Fatal() in the isTrue function. But when you tell the compiler that the isTrue function is a helper function. Then when the test fails the go tool will make it look as if the test failed on the call to the isTrue function, instead of the t.Fatal inside.

More testing: table tests

Let’s write some more tests! Remember that ‘lastIndex’ function form the start of this post? Well, you can say the testing part of that function is quite lacking in the testing part. Because for such a function you would want to cover a lot more cases. And what is an easy way to do that? Indeed, table tests.

Table tests make it easy to have many inputs for the same function. Because each ‘row’ in your ‘table’ has the parameters for that function and the expected result. And the only thing your test has to do, is doing the same thing for each row in the table. And so, you avoid a lot of copy-pasting, editing, and doing the same thing over again because of a darn typo.

Here is an example of how that looks in go:

func TestLastIndex(t *testing.T) {
   tableTests := []struct {
      name string
      list []int
      x    int
      want int
   }{
      {name: "singleElement", list: []int{1}, x: 1, want: 0},
      {name: "2timesTheSame", list: []int{1, 1}, x: 1, want: 1},
      {name: "notFound", list: []int{1, 1, 1, 2, 2, 1}, x: 3, want: -1},
      {name: "firstElement", list: []int{3, 1, 2, 2, 1, 1}, x: 3, want: 0},
   }
   for _, tt := range tableTests { 
      t.Run(tt.name, func(t *testing.T) {
         if got := lastIndex(tt.list, tt.x); got != tt.want {
            t.Errorf("LastIndex(%v, %v) = %v, want %v", tt.list, tt.x, got, tt.want)
         }
      })
   }
}
Github Gist: https://gist.github.com/Coollision/88f9f9e9ff02e74837a06487ea6ef6dd

What is in this test?

First of take a look at the function declaration. Why? Well the syntax hasn’t changed, but this is the way a test is written in go. So now you have checked it out again, you are less likely to forget it :).

Next, we are creating a new struct and assigning it to a variable called ‘table tests’. This is where we define how our test table will look. Afterwards we fill it up with data. What are we putting in there? From the bottom to the top:

want: In this ‘column’ of our table, we put the result we are expecting the lastIndex function to return.

X and list: these the 2 ‘columns’ of our table that define the parameters we are giving to the lastIndex function. The list in which we want to find the last index. And x the number we are looking for in the list.

name: hmm why the name? Because we can actually call each row in the table an individual test. You might even call the rows subtests. And a subtest deserves a name. It gives you the added bonus of filtering for a subtest by using the -run flag when running the tests. Isn’t that nice? :)

Alright, that was the table (struct) and we have filled it up with data. What do we do next? We are going to loop through the data with a simple for each loop. Throw a row from our table in the tt variable.

In the next line, you will find a ‘t.Run(string, func(t *testing.T))’. With this line we are starting a new subtest with the name, given as a string, and the subtests is made up of the function you pass in. When you take a look at the content of the function, it will look a lot like what we wrote in our first test. As in call lastIndex with a list and a number (x), check if the result is what we want, if it is not, fail the test.

And now we have come to the end of our test.

If you want to run it quickly, check it out in the go playground (and do not dare to try and break it ;-) https://play.golang.org/p/TWUbU9OLJXn

Could you make a test fail?

Conclusion

Even though I only covered the basics of writing tests in GoLang and there is still much to talk about, this blog might have helped you with writing some tests for your programs, or even your Lambda functions. But there is still much more to learn when it comes to testing in GoLang.

So keep your eyes open, there will be new posts in the next months. In these posts I’ll tackle testing of functions using the ‘net/http’ package. And also on how to best use mocking and stubbing in tests.

buy the highest quality swiss replica watches. the most rapid logistics and the highest quality service.

Deze website maakt gebruik van cookies om ervoor te zorgen dat u de beste surfervaring op onze website krijgt. Meer info

richard-mille-replica.com