About testing in Go

Alex Romanova - Nov 19 '21 - - Dev Community

This post will be about my pull request that did some tests with Go.

Here's some backstory about why I chose this repo. I've been contributing to 7tv, but I'm also a member of their discord community. There I noticed a project that uses 7tv that was also written in Go. A small project from someone in the same community - likely to explain stuff and help out, shouldn't be too difficult of an app.

So I reached out. You can look at my previous post how that went. Long story short, I decided to try my newly acquired knowledge of testing in a different language. The one I'm really interested in - GO.

How to test?

I researched some basic stuff, official documentation got me started.

Some specific things I noticed:

  • To make a test file, you have to name it NAME_test.go, instead of NAME.test.js compared to JS.
  • Go has a built in testing package, which makes it simple and universal for any GO unit testing.
  • The most useful resource I found is (Go by example)[https://gobyexample.com/testing]. Really shows all you need to begin and make it work. Was even easier than JS, honestly. The table example was really useful too.

What I did

I followed author's advice and made tests for humanize. Those functions have simple string/int input and output. I was happy with how fast I figured things out.

I really a system of testing tables, it looks clean and structured.

You can see that I created variables in my test for arguments and the return value I expect. Then I made a table with those variables united in a single object. That way you can later loop through them and check if that combination works together.

Here's some more code.

  • Function to test:
func StringToSeconds(s string) (int, error) {
    if strings.HasSuffix(s, "m") {
        num := strings.TrimSuffix(s, "m")
        integer, err := strconv.Atoi(num)

        return integer * 60, err
    }

    if strings.HasSuffix(s, "s") {
        num := strings.TrimSuffix(s, "s")
        integer, err := strconv.Atoi(num)

        return integer, err
    }

    integer, err := strconv.Atoi(s)

    return integer, err
}
Enter fullscreen mode Exit fullscreen mode
  • The testing function itself:
func TestStringToSeconds(t *testing.T) {
    var tests = []struct {
        str string
        want int
    }{
        {"60s", 60},
        {"1m", 60},
        {"60m", 3600},//Big example
        {"22s", 22},//Basic example
        {"", 0},//Empty string
        {"10d", 0},//Invalid input
    }

    for _, tt := range tests{
        testname:=fmt.Sprintf("%s", tt.str)
        t.Run(testname, func(t *testing.T) {
            ans, err:=StringToSeconds(tt.str)
            if ans != tt.want {
                fmt.Printf("%s",err)
                t.Errorf("Got %d, want %d", ans, tt.want)
            }
        })
    }
}
Enter fullscreen mode Exit fullscreen mode

There was finally something I could fix through my testing. I figured out that when this following function returns a value with combined units (minutes and seconds), it returns it in a float format, adding a bunch of .000000. Not only it looked bad, it also wasn't consistent with other return values which were ints.

func SecondsToString(s int) string {
    if s < 60 {
        return fmt.Sprintf("%ds", s)
    }
    if s%60 == 0 {
        return fmt.Sprintf("%dm", s/60)
    }

    floored := math.Floor(float64(s) / 60)
    rest := float64(s) - (floored * 60)

    return fmt.Sprintf("%fm %fs", floored, rest)
}
Enter fullscreen mode Exit fullscreen mode

This is how it would look with combined values:

So I actually changed something in the original code to match the format!

...
    floored := int(math.Floor(float64(s) / 60))
    rest := int(float64(s)) - (floored * 60)

    return fmt.Sprintf("%dm %ds", floored, rest)
}
Enter fullscreen mode Exit fullscreen mode

Next level: Mocks?

I was content with myself. I did tests that actually worked. Maybe I can make tests for something more difficult?

So my next quest: How do I mock in go? I went to google. There was a problem. I couldn't find a clear and solid answer. So I went on to ask people who might know.

He showed me his repo where he made a bunch of tests, however I couldn't figure it out. So I went in voice to see what he'll explain..

What he showed was.. a lot. Fast. I couldn't follow. He'd jump from document to document, adding in words I didn't know, and I was really too confused to even form a question. Basically...

And then he went on to build his new chair that apparently had wrong instructions.

So I decided I'll postpone my learning about mocks in Go. After all, I had enough to make a PR where things didn't break yet. I still learned new things. Good enough for me.

YAY I DID SOMETHING NEW IN GO

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Terabox Video Player