Я пишу тесты для слоя repository с использованием реальной базы данных (<a href="https://testcontainers.com/" rel="nofollow">https://testcontainers.com/</a>) и столкнулся с проблемой при проверке структур, содержащих тип time.Time. В качестве примера, вот результат одного из моих тестов: Тест завершается с ошибкой: <pre><code>Error: Not equal: expected: &model.ColorSQL{ID:1, Name:"Cullen Gerhold", CreatedAt:time.Date(2025, time.March, 15, 20, 50, 54, 823874100, time.UTC), UpdatedAt:time.Date(2025, time.March, 15, 20, 50, 54, 823874100, time.UTC), DeletedAt:<nil>} actual : &model.ColorSQL{ID:1, Name:"Cullen Gerhold", CreatedAt:time.Date(2025, time.March, 15, 20, 50, 54, 822076000, time.UTC), UpdatedAt:time.Date(2025, time.March, 15, 20, 50, 54, 822076000, time.UTC), DeletedAt:<nil>}</code></pre> Первая мысль была в том, чтобы обновить код следующим образом: Однако, если я решу обновить структуру и добавлю в нее новые поля, существует риск, что я забуду обновить соответствующие тесты. В результате, тесты могут пройти успешно, даже если новые поля не будут проверяться. Как можно избежать этой проблемы?
Проблемы с проверкой значений типа `time.Time` в тестах достаточно распространены, особенно когда дело касается точности времени, так как даже небольшие изменения могут привести к неравенству. Ваша ситуация показывает, что есть разница в наносекундах между ожидаемым и актуальным значением времени. Вот несколько подходов, которые могут помочь вам решить эту проблему и избежать ошибок в будущем: ### 1. Используйте сравнение без учета наносекунд Если для вашего случая важна только точность до секунд и потенциальные различия в наносекундах можно игнорировать, вы можете сравнивать `time.Time` значения, убирая наносекунды: ```go func equalTimes(t1, t2 time.Time) bool { return t1.Unix() == t2.Unix() && t1.Location() == t2.Location() } ``` Затем в вашем тесте используйте эту функцию вместо прямого сравнения. ### 2. Определите структурированные методы сравнения Если вам требуется более сложная логика для сравнения ваших структур, вы можете определить метод для сравнения полей: ```go type ColorSQL struct { ID int Name string CreatedAt time.Time UpdatedAt time.Time DeletedAt *time.Time } func (c *ColorSQL) Equal(other *ColorSQL) bool { return c.ID == other.ID && c.Name == other.Name && equalTimes(c.CreatedAt, other.CreatedAt) && equalTimes(c.UpdatedAt, other.UpdatedAt) && // Сравнение DeletedAt требует дополнительной логики (c.DeletedAt == nil && other.DeletedAt == nil || (c.DeletedAt != nil && other.DeletedAt != nil && c.DeletedAt.Equal(*other.DeletedAt))) } ``` Теперь вы можете использовать `c.Equal(&actualColor)` для проверки на равенство. ### 3. Стать педантичным в тестах Другая рекомендация заключается в том, чтобы при разработке тестов обеспечивать, что вы проверяете все поля вашей структуры, добавляя больше подробностей в структуру вашего теста: ```go if !expected.Equal(&actual) { t.Errorf("Expected %v but got %v", expected, actual) } ``` ### 4. Mocking времени Иногда полезно использовать библиотеку, которая позволяет "замокировать" текущее время. Одна из таких библиотек - `github.com/jonboulle/clockwork`, которая предоставляет интерфейс для работы с временем. Это может помочь вам избежать вероятностей, связанных с реальным временем. ### 5. Значения по умолчанию Если вы тестируете структуру с временными метками, убедитесь, что значения, которые вы сравниваете, настройте так, чтобы они имели предсказуемые значения времени. Таким образом, вы уменьшаете вероятность различий, вызванных недостаточной точностью. ### Заключение Подобные проблемы довольно типичны при тестировании, и важно использовать инструменты и методы, которые помогут вам избежать ложных срабатываний тестов. Структурируя методы сравнения и хорошо управляя своим временем, вы сможете улучшить надежность и качество тестов.
Первый вариант: Заменить перед сверкой динамическое значение в фактической структуре на ожидаемое.
Второй вариант: Написать свою функцию сравнения полей структуры через reflect с возможностью передачи названий полей, которые не буду сравниваться