Что такое unit тесты

Юнит-тесты (unit tests) — это тесты, предназначенные для проверки корректности работы отдельных модулей или единиц кода, таких как функции или методы. Основная цель юнит-тестов — убедиться, что каждый модуль кода работает как ожидается. Играют ключевую роль в поддержке качества и надежности кода.

Зачем они нужны?

1. Обнаружение ошибок на ранней стадии:

  • Юнит-тесты помогают выявлять ошибки и проблемы в коде на самых ранних этапах разработки, что снижает затраты на их исправление.

2. Документация кода:

  • Хорошо написанные юнит-тесты служат живой документацией для кода, показывая, как именно должны работать функции и методы.

3. Поддержка рефакторинга:

  • Наличие юнит-тестов делает процесс рефакторинга безопаснее, так как тесты помогают убедиться, что изменения в коде не нарушили его корректную работу.

4. Повышение уверенности в коде:

  • Юнит-тесты обеспечивают уверенность в том, что код работает правильно, что особенно важно при добавлении новых функций или исправлении ошибок.

Как их писать?

1. Создание тестовых файлов:

  • Тестовые файлы в Go должны оканчиваться на `_test.go`.
  • Тестовые функции должны начинаться с `Test` и принимать один аргумент типа `*testing.T`.

2. Пример написания юнит-теста:
Рассмотрим пример, где у нас есть функция, которая складывает два числа, и мы пишем для неё юнит-тест.

   ```go
   // main.go
   package main

   func Add(a, b int) int {
       return a + b
   }
   ```
   ```go
   // main_test.go
   package main

   import "testing"

   func TestAdd(t *testing.T) {
       result := Add(2, 3)
       expected := 5
       if result != expected {
           t.Errorf("Add(2, 3) = %d; want %d", result, expected)
       }
   }
   ```

3. Запуск юнит-тестов:

  • Чтобы запустить юнит-тесты, используйте команду `go test` в терминале.
   ```sh
   $ go test
   ```

4. Тестирование с таблицей (table-driven tests):

  • Table-driven tests позволяют легко добавлять новые тестовые случаи и улучшать читаемость тестов.
   ```go
   package main

   import "testing"

   func TestAdd(t *testing.T) {
       tests := []struct {
           a, b, expected int
       }{
           {1, 2, 3},
           {0, 0, 0},
           {-1, -1, -2},
           {2, 2, 4},
       }

       for _, tt := range tests {
           result := Add(tt.a, tt.b)
           if result != tt.expected {
               t.Errorf("Add(%d, %d) = %d; want %d", tt.a, tt.b, result, tt.expected)
           }
       }
   }
   ```

Лучшие практики

1. Соблюдайте атомарность:

  • Каждый юнит-тест должен проверять только одну конкретную функцию или метод и проверять один аспект её поведения.

2. Используйте понятные названия:

  • Имена тестовых функций должны быть понятными и отражать их цель. Например, `TestAdd` для тестирования функции `Add`.

3. Проверяйте крайние случаи:

  • Убедитесь, что ваши тесты проверяют крайние случаи и потенциальные ошибки, такие как нулевые значения, отрицательные числа и переполнения.

4. Регулярно запускайте тесты:

  • Регулярно запускайте тесты, особенно перед коммитами и релизами, чтобы убедиться в отсутствии регрессий.

5. Используйте mocking, если необходимо:

  • При тестировании функций, которые зависят от внешних ресурсов (таких как базы данных или API), используйте мокирование (mocking) для изоляции тестов.

Юнит-тесты проверяют отдельные функции или методы на корректность их работы. Они помогают выявлять ошибки на ранней стадии, служат документацией и поддерживают безопасный рефакторинг кода. Пишутся в файлах с суффиксом `_test.go` и запускаются с помощью команды `go test`.

June 2, 2024, easyoffer

Примеры ответов: