Testing Time: тестируем асинхронный код без time.Sleep в Go 1.25
Пост про testing/synctest в официальном блоге разработчиков Go
- Оригинал
- Хороший перевод
Go Team наконец-то решили давнюю проблему тестирования конкурентного кода. В 1.24 вышел экспериментальный пакет
Очень краткая суть: запускаешь тест в "пузыре" с фейковым временем и ждёшь, пока все горутины станут "устойчиво заблокированными" — то есть могут быть разблокированы только другими горутинами из того же пузыря.
Проблема стара как мир:
- Тестируешь context.WithDeadline — либо ждёшь реальную секунду (медленно), либо не ждёшь достаточно (тест нестабилен, флапает)
- Добавляешь
- Убираешь запас — тест падает на CI под нагрузкой
Классический выбор: slow or flaky, pick... one!
Решение — пузырь с двумя функциями:
-
-
- Время идёт только когда все заблокированы, вычисления занимают 0 времени
- Начало эпохи: полночь 1 января 2000 UTC (как в Go Playground)
Пример до/после:
————
Мне понравилось, что автор также рассказывает про историю создания. Сначала пытались добавить поддержку тестирования прямо в http-пакет — не вышло, особенно с HTTP/2. Потом сделали грязный хак с парсингом
Из ограничений: не работает с реальной сетью (вместо этого нужно использовать их имитацию в памяти — in-memory fake), мьютексы не считаются durably blocking, syscalls и cgo тоже. Но для 95% кейсов — самое то.
Забавно, что самый первый пример в статье — тест для context.WithDeadline. Видимо, это была та самая боль, с которой всё началось🙃
#go1_25 #go_official #testing #concurrency
Пост про testing/synctest в официальном блоге разработчиков Go
- Оригинал
- Хороший перевод
Go Team наконец-то решили давнюю проблему тестирования конкурентного кода. В 1.24 вышел экспериментальный пакет
testing/synctest
, а в 1.25 он стал стабильным.Очень краткая суть: запускаешь тест в "пузыре" с фейковым временем и ждёшь, пока все горутины станут "устойчиво заблокированными" — то есть могут быть разблокированы только другими горутинами из того же пузыря.
Проблема стара как мир:
- Тестируешь context.WithDeadline — либо ждёшь реальную секунду (медленно), либо не ждёшь достаточно (тест нестабилен, флапает)
- Добавляешь
time.Sleep
с запасом — тест тормозит- Убираешь запас — тест падает на CI под нагрузкой
Классический выбор: slow or flaky, pick... one!
Решение — пузырь с двумя функциями:
-
synctest.Test(t, func(t *testing.T) {...})
— запускает функцию в пузыре с фейковым временем-
synctest.Wait()
— ждёт, пока все горутины в пузыре станут "durably blocked"- Время идёт только когда все заблокированы, вычисления занимают 0 времени
- Начало эпохи: полночь 1 января 2000 UTC (как в Go Playground)
Пример до/после:
// Было: медленно и ненадёжно
time.Sleep(time.Until(deadline) + 100*time.Millisecond)
// Стало: быстро и стабильно
synctest.Test(t, func(t *testing.T) {
time.Sleep(time.Until(deadline))
synctest.Wait()
})
————
Мне понравилось, что автор также рассказывает про историю создания. Сначала пытались добавить поддержку тестирования прямо в http-пакет — не вышло, особенно с HTTP/2. Потом сделали грязный хак с парсингом
runtime.Stack()
— работало, но стыдно показать. В итоге добавили поддержку прямо в рантайм.Из ограничений: не работает с реальной сетью (вместо этого нужно использовать их имитацию в памяти — in-memory fake), мьютексы не считаются durably blocking, syscalls и cgo тоже. Но для 95% кейсов — самое то.
Забавно, что самый первый пример в статье — тест для context.WithDeadline. Видимо, это была та самая боль, с которой всё началось
#go1_25 #go_official #testing #concurrency
Please open Telegram to view this post
VIEW IN TELEGRAM
❤9👍5🔥5
🧪 Сравнение инструментов для генерации моков
https://habr.com/ru/companies/avito/articles/939388/
Семён Эйгин из Авито (мейнтейнер minimock) сравнивает три популярных инструмента для генерации моков:
- mockery
- gomock
- minimock
Очевидно, автор предвзят, но статья всё равно интересная. Просто учитывайте это во время чтения.
Какие проблемы обсуждаются:
1. Типизация параметров
- mockery и gomock используют
- minimock генерирует строго типизированные методы:
- На практике: можно пропустить ошибку в стиле
2. Контроль количества вызовов
- gomock по умолчанию разрешает только один вызов метода
- mockery и minimock позволяют неограниченные вызовы
- Двойственная ситуация: gomock помогает поймать лишние вызовы, но требует явного
3. Тестирование асинхронного кода
- mockery: приходится встраивать каналы через
- gomock: нужен самописный хелпер с
- minimock: встроенная поддержка через
————
Выбор автора, предсказуемо — minimock как "самый простой и топорный, покрывающий 99% случаев".
И я в целом согласен: строгая типизация экономит время на дебаге, встроенная поддержка асинхронности избавляет от костылей.
Хотя, я не отношусь к выбору моков настолько же серьёзно — я сам всё ещё использую mockery, потому что описанные его минусы не столь существенны, чтобы мне захотелось взять и перейти на что-то другое.
#article #testing #mocks
https://habr.com/ru/companies/avito/articles/939388/
Семён Эйгин из Авито (мейнтейнер minimock) сравнивает три популярных инструмента для генерации моков:
- mockery
- gomock
- minimock
Очевидно, автор предвзят, но статья всё равно интересная. Просто учитывайте это во время чтения.
Какие проблемы обсуждаются:
1. Типизация параметров
- mockery и gomock используют
interface{}
в ожиданиях: GetUser(1)
интерпретируется как int вместо int64- minimock генерирует строго типизированные методы:
Expect(id int64)
- На практике: можно пропустить ошибку в стиле
(int64=1) != (int=1)
2. Контроль количества вызовов
- gomock по умолчанию разрешает только один вызов метода
- mockery и minimock позволяют неограниченные вызовы
- Двойственная ситуация: gomock помогает поймать лишние вызовы, но требует явного
Times()
или AnyTimes()
3. Тестирование асинхронного кода
- mockery: приходится встраивать каналы через
RunAndReturn
— плохо масштабируется- gomock: нужен самописный хелпер с
controller.Satisfied()
- minimock: встроенная поддержка через
mc.Wait(timeout)
————
Выбор автора, предсказуемо — minimock как "самый простой и топорный, покрывающий 99% случаев".
И я в целом согласен: строгая типизация экономит время на дебаге, встроенная поддержка асинхронности избавляет от костылей.
Хотя, я не отношусь к выбору моков настолько же серьёзно — я сам всё ещё использую mockery, потому что описанные его минусы не столь существенны, чтобы мне захотелось взять и перейти на что-то другое.
#article #testing #mocks
Хабр
Самый лучший мок на свете: разбираемся с инструментами для генерации моков в Go
Всем привет! Меня зовут Семён Эйгин, я бэкендер в Авито , люблю опенсорс и периодически что-то туда контрибьючу. В этой статье разбираемся с моками и выбираем самый удобный инструмент (не обязательно...
50👍10🤔2