DevGang
Авторизоваться

Пишем поддерживаемый код модульного тестирования в Golang

Эта статья посвящена ремонтопригодности кода модульного тестирования, не знаю, писали ли вы когда-нибудь модульный тест в spaghetti-style, который структурирован похожим образом. Честно говоря, я написал довольно много. 


func TestFoo(t *testing.T) {
    // test get
    resp, err := GET(blabalbal)
    assert.Nil(err)
    ...

    // test post
    resp, err = POST(blabalbal)
    assert.Nil(err)
    ...

    // test update
    resp, err = PUT(blabalbal)
    assert.Nil(err)
    ...
}

Большинство людей это пишут для удобства: для инициализации переменных и их повторного использования. Но когда код варианта использования слишком длинный, а единственный текст завершается неудачей, трудно найти конкретную причину, а ее поиск занимает много времени при отладке.

Решения

Платформа тестирования сообщества Go предоставила два более зрелых решения:

  • GoConvey
  • Go testify assert suite

И давайте рассмотрим их по отдельности.

GoConvey

package package_name

import (
    "testing"
    . "github.com/smartystreets/goconvey/convey"
)

func TestSpec(t *testing.T) {
    // Only pass t into top-level Convey calls
    Convey("Given some integer with a starting value", t, func() {
        x := 1

        Convey("When the integer is incremented", func() {
            x++

            Convey("The value should be greater by one", func() {
                So(x, ShouldEqual, 2)
            })
        })

        Convey("When the integer is incremented again", func() {
            x++

            Convey("The value should be greater by one", func() {
                So(x, ShouldEqual, 2)
            })
        })
    })
}

Код, как указан выше, возможен.

Одна из особенностей GoConvey является то, что он выполняется в виде дерева, а не сверху вниз. То есть это пересечение depth-first и не использует общие переменные, так что при выполнении When the integer is incremented (Когда целое число увеличивается) и When the integer is incremented again (Когда целое число увеличивается снова), значение x равно значению 1, присвоенному верхним уровнем.

Приведенный выше код выполняется в следующем порядке.

  • Given some integer... -> When the integer is incremented -> The value should be....
  • Given some integer... -> When the integer is incremented again -> The value should be....

testify assert suite

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

// Define the suite, and absorb the built-in basic suite
// functionality from testify - including a T() method which
// returns the current testing context
type ExampleTestSuite struct {
    suite.Suite
    VariableThatShouldStartAtFive int
}

// Make sure that VariableThatShouldStartAtFive is set to five
// before each test
func (suite *ExampleTestSuite) SetupTest() {
    suite.VariableThatShouldStartAtFive = 5
}

// All methods that begin with "Test" are run as tests within a
// suite.
func (suite *ExampleTestSuite) TestExample() {
    assert.Equal(suite.T(), 5, suite.VariableThatShouldStartAtFive)
    suite.Equal(5, suite.VariableThatShouldStartAtFive)
}

// In order for 'go test' to run this suite, we need to create
// a normal test function and pass our suite to suite.Run
func TestExampleTestSuite(t *testing.T) {
    suite.Run(t, new(ExampleTestSuite))
}

набор в основном с помощью следующих hook функций.

// SetupAllSuite has a SetupSuite method, which will run before the
// tests in the suite are run.
type SetupAllSuite interface {
    SetupSuite()
}

// SetupTestSuite has a SetupTest method, which will run before each
// test in the suite.
type SetupTestSuite interface {
    SetupTest()
}

// TearDownAllSuite has a TearDownSuite method, which will run after
// all the tests in the suite have been run.
type TearDownAllSuite interface {
    TearDownSuite()
}

// TearDownTestSuite has a TearDownTest method, which will run after
// each test in the suite.
type TearDownTestSuite interface {
    TearDownTest()
}

Таким образом, общие переменные, уничтожение и т. д., могут быть помещены в соответствующие функции для обработки, таким образом интегрируя ряд функций в набор тестов.

Заключение

Лично я предпочитаю использовать convey, поскольку, если вы понимаете его древовидный шаблон выполнения, вы обнаружите, что общий тестовый код может быть написан намного меньше, а структура очень понятна. Благодаря древовидной организации можете поместить тестовые примеры одной и той же темы в одну и ту же функцию TestXXX, а затем уточнить их в каждой функции Convey в соответствии с условиями слой за слоем и, наконец, предать утверждения через So для проверки.

В этой статье не говорится о конкретных технических вещах, а в основном кратко представлены две среды модульного тестирования, но самое главное - показать, что код модульного тестирования также должен быть ценным кодом, но также должна быть хорошо организована структура кода и варианты использования, модульные тесты используются для обеспечения выполнения из самого кода, обычно написанного после того, как частота изменений не слишком высока, если использовать организацию в стиле спагетти, после длительного времени очень трудно и долго отлаживать.

С помощью convey вы можете разделить код тестового примера на разные функции, не мешая друг другу, что очень полезно для удобства обслуживания.

#Golang
Комментарии
Чтобы оставить комментарий, необходимо авторизоваться

Присоединяйся в тусовку

В этом месте могла бы быть ваша реклама

Разместить рекламу