Перейти к содержимому
ГоМастер

Поиск по урокам

Найдите урок, курс, термин или раздел

ginkgo или testify: как писать тесты в Go

ginkgo заменяет сам раннер: Describe и It строят дерево спеков, BeforeEach навешивает фикстуры, а CLI рандомизирует и гонит спеки параллельно — с Gomega в придачу. testify остаётся внутри go test: assert и require плюс suite — знакомо каждому и стыкуется со всем стеком.

ginkgotestify suiteкурс

Подбор под ваши приоритеты

Двигайте ползунки — насколько для вас важен каждый критерий (0 — не важен, 5 — критично). Счёт пересчитывается на лету: это взвешенное среднее оценок библиотек по критериям, а не бенчмарк.

Describe и Context против Test-функций и suite

Фокус, рандомизация, параллельность из коробки

Что увидит новичок в первом тесте

go test, табличные тесты, моки, CI

Минуты до первого зелёного теста

Взвешенный счёт

  • testify suiteваш матч84
  • ginkgo72

Под ваши веса лидирует testify suite: командам, которым нужна структура и фикстуры, но важно остаться в go test со стандартным стеком.

Вопрос «ginkgo или testify» всплывает, когда команда устаёт от бесконечных TestStorePutGetOk и хочет структуру: секции, фикстуры, вложенные сценарии. Go из коробки даёт только Test-функции, и два сообщества ответили по-разному. ginkgo пошёл в сторону BDD: тест превращается в дерево спеков Describe, Context и It, фикстуры живут в BeforeEach и AfterEach, а отдельный CLI умет фокус, рандомизацию и параллельность. testify пошёл в сторону усиления стандартного стека: assert и require остаются обычными функциями внутри Test-функций, а для структуры предлагается suite с методами SetupTest и TearDownTest. На этой странице сравним оба подхода по одним критериям, покажем один и тот же тест рядом и соберём персональную рекомендацию ползунками.

ginkgo — это фреймворк вокруг тестов. Файл suites объявляет TestXxx с вызовом RunSpecs, а сами спеки описываются через var _ = Describe: внутри строятся замыкания с It, и каждый It — независимый сценарий, который рантайм ginkgo может перетасовать, зафокусировать через Label или запустить параллельно флагом -p. Ожидания пишутся в стиле Gomega: Expect(x).To(Equal(y)), и у матчейров огромная библиотека — от BeNil до MatchError. Так устроены Kubernetes и заметная часть CNCF-проектов, поэтому в облаке синтаксис встречается буквально повсюду. Расплата — порог входа: дерево спеков строится в момент загрузки, узлы нельзя звать из произвольных замыканий, а новичок должен усвоить и RunSpecs, и BeforeEach, и Gomega до первого зелёного теста.

testify — это надстройка над go test, а не замена. Тест остаётся обычной функцией TestXxx, структура добирается suite-ами: встраиваете suite.Suite, описываете SetupTest и TearDownTest, а каждый метод TestXxx превращается в отдельный тест с хуками. Assert пишутся как s.Equal(want, got) или assert.Equal(t, want, got), табличные тесты не конфликтуют со структурой, а всё выученное работает и в gomock, и в http-тестах, и в CI без единого нового инструмента. Расплата — раннер: рандомизации порядка нет, параллельность запускается вручную через t.Parallel, фокус на спеке делается пропуском t.Run, а сам suite заметно скучнее Describe и Context для больших сценариев.

Как читать итог ниже: оценки — усреднение практики команды проекта, а не замеры; ползунки подставляют ваши приоритеты. Грубая граница: большой облачный проект со сложными сценариями и потребностью в управляемом раннере — ginkgo с Gomega; команда, которая хочет структуры, но остаться в go test со стандартным стеком — testify suite. Честный третий путь — совмещать testify-assert внутри ginkgo-спеков, но чаще выбирают одну из двух сторон, чтобы не смешивать словари ожиданий.

Одна и та же задача в каждой библиотеке

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

BDD-фреймворк: дерево спеков, управляемый раннер и Gomega

package store_test

import (
  "testing"

  . "github.com/onsi/ginkgo/v2"
  . "github.com/onsi/gomega"
)

func TestStore(t *testing.T) {
  RegisterFailHandler(Fail)
  RunSpecs(t, "Store Suite")
}

var _ = Describe("Store", func() {
  var s *Store

  BeforeEach(func() {
    s = NewStore()
  })

  It("сохраняет и возвращает пользователя", func() {
    err := s.Put("Аня", 7)
    Expect(err).ToNot(HaveOccurred())

    got, ok := s.Get("Аня")
    Expect(ok).To(BeTrue())
    Expect(got).To(Equal(7))
  })
})

Сильные и слабые стороны

ginkgo

BDD-фреймворк: дерево спеков, управляемый раннер и Gomega

  • Структура больших сценариев: Describe, Context и It делают вложенность читаемой даже на сотни спеков
  • Серьёзный раннер: ginkgo умеет фокус по Label, рандомизацию порядка и параллельный прогон из коробки
  • Gomega-матчеры: Expect с To, HaveOccurred, MatchError и богатая библиотека проверок
  • Порог входа: RunSpecs, BeforeEach и правила построения дерева надо усвоить до первого теста
  • Своя лексика: Gomega живёт рядом с assert-привычками, команды смешивают словари ожиданий
  • Свой CLI: часть привычек go test не переносится, тесты запускаются через ginkgo

Берите, если: большим проектам со сложными сценариями и командам, которые хотят управляемый раннер и bdd-структуру.

testify suite

Структура без смены раннера: suite с хуками поверх go test

  • Знакомый мир: обычный go test, обычные assert, ничего нового в CI и терминале
  • Suite с хуками: SetupTest и TearDownTest дают фикстуры без дерева замыканий
  • Один стек: assert, require, моки и suites переиспользуются во всех проектах на Go
  • Скучный раннер: рандомизации нет, параллельность и фокус делаются руками через t.Parallel и t.Run
  • Слабее вложенность: под-сценарии выражаются методами или табличными тестами, а не Context
  • Suite-методы прячут t: ошибки привязываются внутри хелперов, новичку надо привыкнуть к s.Equal

Берите, если: командам, которым нужна структура и фикстуры, но важно остаться в go test со стандартным стеком.

Оценки по критериям

Шкала 1-5: экспертная оценка команды проекта по практике, а не синтетика.

Сравнение ginkgo, testify suite по критериям
Критерийginkgotestify suite
Организация спековDescribe и Context против Test-функций и suite
Раннер и CLIФокус, рандомизация, параллельность из коробки
Порог входаЧто увидит новичок в первом тесте
Стыковка со стекомgo test, табличные тесты, моки, CI
Скорость написанияМинуты до первого зелёного теста

Вердикт: когда что выбирать

ginkgo меняет сам способ запускать тесты: дерево спеков, управляемый CLI, рандомизация и параллельность — ценой нового словаря и CLI-зависимости. testify меняет только запись: assert и suite остаются в привычном go test — ценой скучного раннера и слабой вложенности. Kubernetes-экосистема живёт в ginkgo, обычный бэкенд чаще — в testify.

Большой проект со сложными сценариями и несколькими пакетамиginkgoDescribe и Context держат структуру, а раннер управляет фокусом и параллельностью
Команда хочет структуру, но остаться в go testtestify suiteSetupTest и TearDownTest дают фикстуры без смены раннера и CI
Новые тестировщики и джуновский онбордингtestifyОдин assert-словарь от юнит-тестов до моков — меньше порог входа
Кластер Kubernetes или CNCF-проектginkgoЭкосистема вокруг живёт на ginkgo и Gomega — конвенции важнее вкусов

А что выбрали вы?

Кликните по своему выбору — голос сохранится только в вашем браузере (персональные данные никуда не отправляются).

Частые вопросы

Что выбрать — ginkgo или testify?

Опирайтесь на масштаб и экосистему. Сотни спеков, вложенные сценарии, желание управлять порядком и параллельностью — ginkgo с Gomega: так устроены Kubernetes и многие облачные проекты. Обычный сервис, который должен остаться в go test с табличными тестами и единым assert-стеком — testify suite. Смешивать можно, но команды обычно выбирают один словарь ожиданий, чтобы тесты читались одинаково.

Почему ginkgo считается сложнее для новичков?

Помимо самих проверок, новичок должен усвоить структуру фреймворка: спеки объявляются через var _ = Describe, дерево строится при загрузке, узлы нельзя звать из произвольных замыканий, а фикстуры раскладываются по BeforeEach и AfterEach. В testify первый тест — это метод с s.Equal внутри привычной Test-функции: человек читает обычный Go, а не соглашения фреймворка, поэтому старт быстрее и ошибки проще.

Можно ли использовать Gomega-матчеры без ginkgo?

Да — Gomega самостоятелен: Expect(x).To(Equal(y)) вызывается и внутри обычных go test через RegisterFailHandler с подключением testing.T. Некоторые команды берут именно эту пару: структуру оставляют в Test-функциях и suite-ах, а проверки пишут матчера́ми Gomega, потому что они выразительнее для вложенных структур и ошибок. Это честный компромисс между мирами ginkgo и testify.

А где в этой картине моки?

Моки ортогональны выбору раннера: в testify-мире это testify/mock или mockery, в ginkgo-мире чаще gomock — и то и другое работает с любым раннером, потому что моки это код, а не фреймворк. У нас есть отдельные сравнения: gomock против testify/mock — для выбора мок-подхода, а про то, как моки живут внутри suite-ов, подробно рассказано в уроке курса testify про ожидания.

Другие сравнения