3cheesewheel
3cheesewheel

Reputation: 9653

Is it possible to dynamically assert if two values are equal or not equal when unit testing in Go?

I've just started using Go. I'm writing unit tests and I'd like to be able to test using a table, where the result to be compared to the actual result sometimes should or should not be equal.

For example, this is the code that I currently have:

package main

import (
    "github.com/stretchr/testify/assert"
    "testing"
)

func TestFunc(t *testing.T) {
    tables := []struct {
        input               string
        comparisonResult    string
        shouldBeEqual       bool
    }{
        {
            "some irrelevant input",
            "some result",
            true,
        },
        {
            "some other irrelevant input",
            "some other result",
            false,
        },
    }

    for _, table := range tables {
        actualResult := sampleFunc(table.input)
        if table.shouldBeEqual {
            assert.Equal(t, table.expectedResult, actualResult)
        } else {
            assert.NotEqual(t, table.expectedResult, actualResult)
        }
    }
}

Now, this isn't too bad, but it would be even better if the last bit could be changed to something cleaner like this for better readability:

for _, table := range tables {
    actualResult := sampleFunc(table.input)
    assert.EqualOrNotEqual(t, table.comparisonResult, actualResult, table.shouldBeEqual)
}

So, the first test should pass if table.comparisonResult and actualResult are equal, and the second test should pass if the two aren't equal.

I've looked through the testify/assert docs and I don't think I found a function that is similar to the fake EqualOrNotEqual function that I made up above, but perhaps I accidentally skipped over something, or there is some kind of Go special syntax that I don't know about that might help me achieve this.

Note: I am well aware that I can write my own function for this. My reason for asking was because if this is a well-established pattern, then packages/libraries often include it as a built-in function which may at times be undocumented/buried in the documentation. And if not, maybe there's a reason why I shouldn't do this, or maybe there's a better way of doing it. Starting to use a new language is very labour-intensive at first, not least because you have to learn all the new idioms and quirks and The Right Way to do things.

Upvotes: 2

Views: 7510

Answers (2)

Harald Nordgren
Harald Nordgren

Reputation: 12409

Golang does have a functional aspect, although it's more rigid than in Python or JavaScript.

You can allow your struct table to hold functions if you know their signatures. Then you get rid of the if logic inside the tests:

func TestFunc(t *testing.T) {
    tables := []struct {
        input            string
        comparisonResult string
        assert           func(assert.TestingT, interface{}, interface{}, ...interface{}) bool
    }{
        {
            input:            "some irrelevant input",
            comparisonResult: "some result",
            assert:           assert.Equal,
        },
        {
            input:            "some other irrelevant input",
            comparisonResult: "some other result",
            assert:           assert.NotEqual,
        },
    }

    for _, table := range tables {
        actualResult := sampleFunc(table.input)
        table.assert(t, table.comparisonResult, actualResult)
    }
}

Upvotes: 0

Will
Will

Reputation: 4469

Since it's just for readability, and since it appears that this function does not exist, you could just copy-paste your working code into a separate function:

func equalOrNotEqual(t TestingT, expected, actual interface{}, shouldBeEqual bool) {
    if shouldBeEqual {
        assert.Equal(t, expected, actual)
    } else {
        assert.NotEqual(t, expected, actual)
    }
}

and:

for _, table := range tables {
    actualResult := sampleFunc(table.input)
    equalOrNotEqual(t, table.comparisonResult, actualResult, table.shouldBeEqual)
}

Upvotes: 2

Related Questions