BDD на Go: Как писать тесты, которые понимает бизнес

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Когда код превращается в историю

Представьте: вы пишете код на Go, запускаете тесты — зелёная полоска. Но менеджер смотрит на ваш t.Errorf и не понимает, что именно сломалось. Бизнес говорит: «Сделайте так, чтобы пользователь мог зарегистрироваться», а разработчик переводит это в «POST /api/v1/user с валидацией email». Разрыв между техническим и человеческим языком — главная головная боль многих проектов.

Решение есть — BDD (Behaviour-Driven Development) на Go. Это не просто тесты. Это мост между кодом и бизнес-логикой. В этой статье мы разберём, как писать BDD-тесты на Go, используя реальные примеры, и почему ваш продакт-менеджер будет вам благодарен.

Что такое BDD и почему Go?

Behaviour-Driven Development (разработка через поведение) — это эволюция TDD. Если TDD фокусируется на «как» (как реализовать функцию), то BDD отвечает на «что» (что должна делать система с точки зрения пользователя).

Go идеально подходит для BDD благодаря своей простоте, встроенному пакету testing и мощным фреймворкам вроде Ginkgo и Godog. Go-сообщество активно использует BDD для микросервисов, API и даже CLI-утилит.

Ключевые принципы BDD на Go

  • Единый язык (Ubiquitous Language) — сценарии пишутся на понятном бизнесу английском или русском.
  • Given-When-Then — структура любого сценария: предпосылки → действие → ожидаемый результат.
  • Автоматизация — сценарии превращаются в исполняемые тесты на Go.

Инструменты для BDD в Go

Выбор фреймворка зависит от того, как вы хотите описывать сценарии. Вот два основных подхода:

1. Ginkgo + Gomega (для Go-разработчиков)

Ginkgo — это BDD-фреймворк, который пишется на чистом Go. Сценарии выглядят как Go-код с читаемыми описаниями. Gomega — библиотека матчеров для ассертов.

Плюсы: полный контроль над кодом, отличная интеграция с Go-тулингом, поддержка асинхронных тестов.

2. Godog (Cucumber для Go)

Godog — это имплементация Cucumber на Go. Вы пишете сценарии на Gherkin (Feature-файлы на естественном языке), а затем реализуете шаги на Go.

Плюсы: сценарии читают даже не-программисты, легко менять логику без правки кода.

Практика: пишем BDD-тест на Go с Ginkgo

Давайте создадим простой сервис — корзину интернет-магазина. Напишем BDD-тест, который проверяет добавление товара.

Шаг 1: Установка Ginkgo

go get github.com/onsi/ginkgo/v2
go get github.com/onsi/gomega

Шаг 2: Инициализация тестового пакета

cd mycart
ginkgo bootstrap

Создаётся файл mycart_suite_test.go.

Шаг 3: Пишем сценарий

Создадим файл cart_test.go:

package mycart_test

import (
    . "github.com/onsi/ginkgo/v2"
    . "github.com/onsi/gomega"
    "mycart"
)

var _ = Describe("Корзина", func() {
    var cart *mycart.Cart

    BeforeEach(func() {
        cart = mycart.NewCart()
    })

    Describe("Добавление товара", func() {
        Context("с корректным ID и ценой", func() {
            It("должна увеличить количество элементов на 1", func() {
                cart.AddItem("sku-123", 100.0)
                Expect(cart.TotalItems()).To(Equal(1))
            })

            It("должна корректно считать общую сумму", func() {
                cart.AddItem("sku-123", 100.0)
                cart.AddItem("sku-456", 250.0)
                Expect(cart.TotalPrice()).To(BeNumerically("~", 350.0, 0.01))
            })
        })

        Context("с товаром, который уже есть", func() {
            It("должна увеличить количество, а не добавлять новый элемент", func() {
                cart.AddItem("sku-123", 100.0)
                cart.AddItem("sku-123", 100.0)
                Expect(cart.TotalItems()).To(Equal(1))
                Expect(cart.Quantity("sku-123")).To(Equal(2))
            })
        })
    })
})

Шаг 4: Реализация кода

package mycart

type Cart struct {
    items map[string]*Item
}

type Item struct {
    SKU      string
    Price    float64
    Quantity int
}

func NewCart() *Cart {
    return &Cart{items: make(map[string]*Item)}
}

func (c *Cart) AddItem(sku string, price float64) {
    if item, ok := c.items[sku]; ok {
        item.Quantity++
    } else {
        c.items[sku] = &Item{SKU: sku, Price: price, Quantity: 1}
    }
}

func (c *Cart) TotalItems() int {
    return len(c.items)
}

func (c *Cart) TotalPrice() float64 {
    total := 0.0
    for _, item := range c.items {
        total += item.Price * float64(item.Quantity)
    }
    return total
}

func (c *Cart) Quantity(sku string) int {
    if item, ok := c.items[sku]; ok {
        return item.Quantity
    }
    return 0
}

Шаг 5: Запуск тестов

ginkgo -v

Вы увидите читаемый вывод: «Корзина Добавление товара с корректным ID и ценой должна увеличить количество элементов на 1 — PASSED». Это и есть BDD в действии.

BDD с Godog: сценарии на русском языке

Если ваша команда включает аналитиков или менеджеров, используйте Godog. Сценарии пишутся на Gherkin.

Установка Godog

go get github.com/cucumber/godog/cmd/godog

Feature-файл (cart.feature)

Функция: Корзина покупок
  Как покупатель
  Я хочу добавлять товары в корзину
  Чтобы оформить заказ

  Сценарий: Добавление нового товара
    Допустим корзина пуста
    Когда я добавляю товар "sku-123" с ценой 100
    Тогда в корзине 1 элемент
    И общая сумма равна 100

Реализация шагов (cart_steps.go)

package main

import (
    "github.com/cucumber/godog"
    "mycart"
)

var cart *mycart.Cart

func iCartIsEmpty() error {
    cart = mycart.NewCart()
    return nil
}

func iAddItemWithPrice(sku string, price float64) error {
    cart.AddItem(sku, price)
    return nil
}

func cartHasItems(count int                

Блоги

Рекомендаций по книгам