Go: Система тестирования на основе BDD: введение и практика Ginkgo
Go: Система тестирования на основе BDD: введение и практика Ginkgo

Введение

В статье «Как эффективно тестировать код Go» мы говорили о модульном тестировании и предлагали решения для интерфейсных и фиктивных зависимостей, позволяющие решить две основные проблемы: развязку и зависимость. В то же время в этой статье также обсуждаются некоторые практические инструменты тестирования в области Go, читатели могут ее прочитать. В центре внимания модульного тестирования находится логическая единица кода, обычно объект или конкретная функция. Мы можем написать достаточное количество модульных тестов, чтобы гарантировать качество кода. Когда функции изменяются или код подвергается рефакторингу, достаточное количество случаев модульного тестирования может дать нам достаточную уверенность. Над модульными тестами находятся спецификации разработки. В гибкой разработке программного обеспечения часто встречаются два человека: разработка через тестирование (TDD) и разработка через поведение (BDD). Это не только практики и методы, но и методологии проектирования.

1. TDD

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

  • Разработчики сначала пишут несколько вариантов использования,
  • Запустите этот тест,Но этот тест явно провалится,Потому что бизнес-логика в тестовом варианте использования еще не реализована.
  • Детали кода реализации
  • Если разработчик успешно реализует код, все тесты будут пройдены.
  • Своевременно проводите рефакторинг бизнес-кода,Если новый код работает неправильно,Соответствующий тестовый файл также не будет работать.

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

Есть интересный репозиторий на Github: Learn-go-with-tests, предназначенный для изучения TDD с помощью Go.

2. BDD

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

3. Ginkgo

Ginkgo — это среда тестирования BDD на языке Go, призванная помочь разработчикам писать выразительные и комплексные тесты. Ginkgo интегрируется с собственными библиотеками Go, что означает, что вы можете запускать набор тестов Ginkgo через . В то же время он также совместим с набором утверждений и макетов, а также с богатым набором тестов для проверки. Но Ginkgo рекомендует использовать его с библиотекой gomega.

10 часто используемых модулей Ginkgo: It, Context, Describe, BeforeEach, AfterEach, JustBeforeEach, BeforeSuite, AfterSuite, By, Fail

  • Базовая единица примера Itdatest,То есть код, который он содержит, считается вариантом использования.
  • Функция ContextиDescribe заключается в категоризации одного или нескольких экземпляров.
  • BeforeEachда Выполняйте этот код перед выполнением каждого экземпляра теста.
  • AfterEachда Выполняйте этот код после выполнения каждого экземпляра теста.
  • JustBeforeEachда выполняется после выполнения BeforeEach и до выполнения тестового примера.
  • BeforeSuiteда выполняется до выполнения тестового набора, то есть до выполнения тестовых примеров в папке.
  • AfterSuiteда выполняется после выполнения тестового набора, то есть после выполнения тестовых примеров в папке.
  • Byда Распечатать информацию,Содержимое может быть только строкой,Будет распечатано только в том случае, если тестовый пример не пройден.,Обычно используется для отладки и поиска проблем.
  • Неудачный далоготип Этот тестовый пример завершается неудачей и печатает содержащуюся в нем информацию.
  • Существует также Specify, который имеет точно такую ​​же функцию, что и It, и это его аббревиатура.

1. Практика гинкго

1. Установите Гинкго
Язык кода:javascript
копировать
go get github.com/onsi/ginkgo/ginkgo 
go get github.com/onsi/gomega/...
2. Используйте

Создайте тестовую папку, например, example, войдите в папку, выполните команду ginkgo bootstrap, чтобы сгенерировать файл шаблона, имя файла — example_suite_test.go, в нем есть функция ввода для выполнения примера создания гинкго, пример не требуется. написано, по умолчанию используется имя текущей папки, сгенерируйте тест. Пример файла шаблона example_test.go добавляет суффикс _test, чтобы отличить его от существующего кода в текущей папке. Код example_test.go по умолчанию импортирует текущую папку.

Язык кода:javascript
копировать
var _ = Describe(“Book”, func() { 
	var ( 
		book Book 
		err error 	
		json string 
	)
	BeforeEach(func() { 
		json = `{ 
			"title":"Les Miserables", 
			"author":"Victor Hugo", 
			"pages":1488 
		}` 
	})
	
	JustBeforeEach(func() { 
		book, err = NewBookFromJSON(json) 
	})
	
	AfterEach(func() { 
		By("End One Test") 
	})
	
	Describe("loading from JSON", func() { 
		Context("when the JSON parses succesfully", func() { 
			It("should populate the fields correctly", func() { 
				Expect(book.Title).To(Equal("Les Miserables")) 
				Expect(book.Author).To(Equal("Victor Hugo")) 
				Expect(book.Pages).To(Equal(1488)) 
			}) 
			It("should not error", func() { 
				Expect(err).NotTo(HaveOccurred()) 
			}) 
		}) 
		Context("when the JSON fails to parse", func() { 
			BeforeEach(func() { 
				json = `{ 
					"title":"Les Miserables", 
					"author":"Victor Hugo", 
					"pages":1488oops 
				}` 
			}) 
			It("should return the zero-value for the book", func() { 
				Expect(book).To(BeZero()) 
			}) 
			It("should error", func() { 
				if err != nil { 
					Fail("This Case Failed") 
				} 
			})
		}) 
	})
	Describe("Extracting the author's last name", func() { 
		It("should correctly identify and return the last name", func(){
			Expect(book.AuthorLastName()).To(Equal("Hugo")) 
		}) 
	}) 
})

Как видите, сначала определяются глобальные переменные book, err и json. Пять тестовых примеров разделены на две основные категории, различающиеся двумя описаниями. Первая категория разделена на две небольшие категории, различающиеся контекстом. Каждый It содержит тестовый пример. Состоит из двух BeforeEach, каждый из которых работает только в пределах текущего домена. Последовательность выполнения — это последовательное выполнение одного и того же уровня и выполнение разных уровней от внешнего слоя к внутреннему. AfterEach правило меняется на противоположное. AfterEach обычно используется для очистки данных после завершения выполнения тестового примера, а также может использоваться для оценки результатов. Старайтесь не присваивать значения переменным в var, поскольку каждый раз при выполнении тестового примера значение глобальная переменная может быть изменена, что вызовет проблемы для последующих тестовых примеров Influence, ее правильнее записать в BeforeEach.

Язык кода:javascript
копировать
func TestBooks(t *testing.T) { 
	RegisterFailHandler(Fail) 
	RunSpecs(t, "Books Suite") 
}

var _ = BeforeSuite(func() { 
	dbRunner = db.NewRunner() 
	err := dbRunner.Start() 
	Expect(err).NotTo(HaveOccurred())

	dbClient = db.NewClient() 
	err = dbClient.Connect(dbRunner.Address()) 
	Expect(err).NotTo(HaveOccurred()) 
})

var _ = AfterSuite(func() { 
	dbClient.Cleanup() 
	dbRunner.Stop() 
})

BeforeSuite и AfterSuite записаны в файле _suite_test.go и будут выполняться до и после выполнения всех тестовых случаев. Если BeforeSuite не запускается, этот набор тестов не будет выполнен.

Совет: При использовании C для прерывания выполнения AfterSuite все равно будет выполняться, и вам придется использовать C для прерывания еще раз.

2. Расширенное использование

1. Логотип

Их три: Ф,

Язык кода:javascript
копировать
FDescribe(“outer describe”, func() { 
	It(“A”, func() { … }) 
	It(“B”, func() { … }) 
}) 

Совет: Если фокус существует как во внутреннем, так и во внешнем слоях, внешний слой недействителен, то есть следующий код выполнит только тестовый пример B.

Язык кода:javascript
копировать
FDescribe(“outer describe”, func() { 
	It(“A”, func() { … }) 
	FIt(“B”, func() { … }) 
})

Значение P — «Ожидание», то есть не выполняется. Использование такое же, как F. Внешний уровень правила вступает в силу. X имеет то же значение, что и P. Другой способ пропустить тестовые примеры — добавить его.

Язык кода:javascript
копировать
Skip It(“should do something, if it can”, func() { 
	if !someCondition { 
		Skip(“special condition wasn’t met”) 
	}
}) 
2. Параллелизм

ginkgo -p использует количество параллелизма по умолчанию, ginkgo -nodes=N Установите количество параллелизма самостоятельно. Число параллелизма по умолчанию — это значение параметра runtime.NumCPU(), которое представляет собой количество логических процессоров. Если оно больше 4, используйте runtime.NumCPU()-1. во время одновременного выполнения суммируются и объединяются. Он обрабатывается, а затем печатается, поэтому он выглядит более стандартизированным. Содержимое каждого тестового примера также печатается вместе, но не в реальном времени. Если вам нужно печатать в реальном времени, добавьте. параметр -stream. Недостаток заключается в том, что каждый журнал тестовых случаев печатается перекрестно.

3. goroutine
Язык кода:javascript
копировать
It(“should post to the channel, eventually”, func(done Done) { 
	c := make(chan string, 0)
	go DoSomething(c) 
	Expect(<-c).To(ContainSubstring("Done!")) 
	close(done) 
}, 0.2)
Гинкго обнаруживает параметр типа «Готово»,Тайм-аут будет установлен автоматически,Всего на 0,2 позади да,Единица измерения в секунду
4. Использование таблицы описания

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

Язык кода:javascript
копировать
package table_test 
import ( 
	. “github.com/onsi/ginkgo/extensions/table” 
	. "github.com/onsi/ginkgo" 
	. "github.com/onsi/gomega" 
) 

var _ = Describe(“Math”, func() { 
	DescribeTable(“the > inequality”, 
		func(x int, y int, expected bool) { 
			Expect(x > y).To(Equal(expected)) 
		}, 
		Entry(“x > y”, 1, 0, true), 
		Entry(“x == y”, 0, 0, false), 
		Entry(“x < y”, 0, 1, false), 
	) 
})

Эквивалентно

Язык кода:javascript
копировать
package table_test import ( 
	. “github.com/onsi/ginkgo” 
	. “github.com/onsi/gomega” 
) 
var _ = Describe(“Math”, func() { 
	Describe(“the > inequality”, 
		It(“x > y”, func() { 
			Expect(1 > 0).To(Equal(true)) 
		})
		It("x == y", func() { 
			Expect(0 > 0).To(Equal(false)) 
		}) 
		It("x < y", func() { 
			Expect(0 > 1).To(Equal(false)) 
		}) 
	) 
})
4. Создайте отчет о тестировании JUnit.

Обычно генерирует отчет о тестировании Junit XML

Язык кода:javascript
копировать
func TestFoo(t *testing.T) { 
	RegisterFailHandler(Fail) 
	junitReporter := reporters.NewJUnitReporter("junit.xml")
	RunSpecsWithDefaultAndCustomReporters(t, "Foo Suite", []Reporter{junitReporter}) 
}
6. Производительность тестового примера

Использование модуля «Измерение»

Язык кода:javascript
копировать
Measure(“it should do something hard efficiently”, func(b Benchmarker) { 
	runtime := b.Time(“runtime”, func() { 
		output := SomethingHard() 
		Expect(output).To(Equal(17)) 
	})
	Ω(runtime.Seconds()).Should(BeNumerically("<", 0.2), "SomethingHard() shouldn't take too long.") 
	b.RecordValue("disk usage (in MB)", HowMuchDiskSpaceDidYouUse()) 
}, 10)

Этот тестовый пример будет запущен 10 раз, и данные о производительности выполнения будут распечатаны.

Язык кода:javascript
копировать
• [MEASUREMENT] 
Suite 
it should do something hard efficiently 

Ran 10 samples: 
runtime: 
	Fastest Time: 0.01s 
	Slowest Time: 0.08s 
	Average Time: 0.05s ± 0.02s 

disk usage (in MB): 
	Smallest: 3.0 
	Largest: 5.2 
	Average: 3.9 ± 0.4

краткое содержание

DD и BDD — это методологии, часто упоминаемые в гибкой разработке. По сравнению с TDD, BDD стимулирует разработку программного обеспечения путем написания поведения и спецификаций. Такое поведение и спецификации отражаются в более «подробном» описании кода. Есть еще один способ выразить суть BDD: BDD помогает разработчикам разрабатывать программное обеспечение, а TDD помогает разработчикам тестировать программное обеспечение. Ginkgo — отличная платформа BDD на языке Go. Она эффективно помогает разработчикам организовывать и организовывать тестовые сценарии с помощью синтаксиса DSL (Describe/Context/It). В этой статье показан только очень простой вариант использования гинкго, и ее следует использовать в качестве отправной точки. При использовании Ginkgo читателям необходимо понимать жизненный цикл его выполнения, уделяя особое внимание последовательности выполнения и семантической логике этих модулей. Ginkgo имеет множество функций, не описанных в этой статье, таких как асинхронное тестирование, эталонное тестирование, непрерывная интеграция и другая мощная поддержка. Его склад расположен по адресу https://github.com/onsi/ginkgo. Он также предоставляет английскую и китайскую версии документации по использованию. Читатели могут использовать его, чтобы узнать больше о Ginkgo. Наконец, платформа Ginkgo также используется в проекте K8s для написания сквозных (E2E) тестовых примеров, чему стоит поучиться.

Ссылка: https://view.inews.qq.com/a/20220711A0270R00.

boy illustration
Неразрушающее увеличение изображений одним щелчком мыши, чтобы сделать их более четкими артефактами искусственного интеллекта, включая руководства по установке и использованию.
boy illustration
Копикодер: этот инструмент отлично работает с Cursor, Bolt и V0! Предоставьте более качественные подсказки для разработки интерфейса (создание навигационного веб-сайта с использованием искусственного интеллекта).
boy illustration
Новый бесплатный RooCline превосходит Cline v3.1? ! Быстрее, умнее и лучше вилка Cline! (Независимое программирование AI, порог 0)
boy illustration
Разработав более 10 проектов с помощью Cursor, я собрал 10 примеров и 60 подсказок.
boy illustration
Я потратил 72 часа на изучение курсорных агентов, и вот неоспоримые факты, которыми я должен поделиться!
boy illustration
Идеальная интеграция Cursor и DeepSeek API
boy illustration
DeepSeek V3 снижает затраты на обучение больших моделей
boy illustration
Артефакт, увеличивающий количество очков: на основе улучшения характеристик препятствия малым целям Yolov8 (SEAM, MultiSEAM).
boy illustration
DeepSeek V3 раскручивался уже три дня. Сегодня я попробовал самопровозглашенную модель «ChatGPT».
boy illustration
Open Devin — инженер-программист искусственного интеллекта с открытым исходным кодом, который меньше программирует и больше создает.
boy illustration
Эксклюзивное оригинальное улучшение YOLOv8: собственная разработка SPPF | SPPF сочетается с воспринимаемой большой сверткой ядра UniRepLK, а свертка с большим ядром + без расширения улучшает восприимчивое поле
boy illustration
Популярное и подробное объяснение DeepSeek-V3: от его появления до преимуществ и сравнения с GPT-4o.
boy illustration
9 основных словесных инструкций по доработке академических работ с помощью ChatGPT, эффективных и практичных, которые стоит собрать
boy illustration
Вызовите deepseek в vscode для реализации программирования с помощью искусственного интеллекта.
boy illustration
Познакомьтесь с принципами сверточных нейронных сетей (CNN) в одной статье (суперподробно)
boy illustration
50,3 тыс. звезд! Immich: автономное решение для резервного копирования фотографий и видео, которое экономит деньги и избавляет от беспокойства.
boy illustration
Cloud Native|Практика: установка Dashbaord для K8s, графика неплохая
boy illustration
Краткий обзор статьи — использование синтетических данных при обучении больших моделей и оптимизации производительности
boy illustration
MiniPerplx: новая поисковая система искусственного интеллекта с открытым исходным кодом, спонсируемая xAI и Vercel.
boy illustration
Конструкция сервиса Synology Drive сочетает проникновение в интрасеть и синхронизацию папок заметок Obsidian в облаке.
boy illustration
Центр конфигурации————Накос
boy illustration
Начинаем с нуля при разработке в облаке Copilot: начать разработку с минимальным использованием кода стало проще
boy illustration
[Серия Docker] Docker создает мультиплатформенные образы: практика архитектуры Arm64
boy illustration
Обновление новых возможностей coze | Я использовал coze для создания апплета помощника по исправлению домашних заданий по математике
boy illustration
Советы по развертыванию Nginx: практическое создание статических веб-сайтов на облачных серверах
boy illustration
Feiniu fnos использует Docker для развертывания личного блокнота Notepad
boy illustration
Сверточная нейронная сеть VGG реализует классификацию изображений Cifar10 — практический опыт Pytorch
boy illustration
Начало работы с EdgeonePages — новым недорогим решением для хостинга веб-сайтов
boy illustration
[Зона легкого облачного игрового сервера] Управление игровыми архивами
boy illustration
Развертывание SpringCloud-проекта на базе Docker и Docker-Compose