Skip to content

Тестовые утилиты

DD предоставляет LoggerRecorder для сценария тестирования, позволяющий захватывать записи логов для проверок.

LoggerRecorder

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

Ограничение парсинга текстового формата

Парсер текстового режима предполагает использование формата времени по умолчанию (ISO 8601) и строк уровня по умолчанию (DEBUG/INFO/WARN/ERROR/FATAL). Если вы настроили TimeFormat, текстовый режим может не корректно извлечь уровень и временную метку. Для пользовательских форматов рекомендуется использовать формат JSON (FormatJSON), настраиваемый через SetFormat.

Создание

go
recorder := dd.NewLoggerRecorder()

Основные методы

МетодСигнатураОписание
Writer() io.WriterПолучить io.Writer
SetFormat(format LogFormat)Установить формат логов (для парсинга)
NewLogger(cfg ...Config) (*Logger, error)Создать Logger, записывающий в этот рекордер
Entries() []LogEntryПолучить все записи логов
Count() intКоличество записей
Clear()Очистить все записи
HasEntries() boolЕсть ли записи
LastEntry() *LogEntryПоследняя запись (nil-безопасный)

Методы проверки

МетодСигнатураОписание
EntriesAtLevel(level LogLevel) []LogEntryФильтрация записей по уровню
ContainsMessage(msg string) boolСодержит ли указанное сообщение (точное совпадение или подстрока)
ContainsField(key string) boolСодержит ли указанное поле
GetFieldValue(key string) anyПолучить значение первого совпадающего поля

Примеры использования

Базовый тест

go
func TestLogger(t *testing.T) {
    rec := dd.NewLoggerRecorder()
    logger, _ := rec.NewLogger()

    logger.Info("hello")
    logger.Warn("warning")

    if rec.Count() != 2 {
        t.Errorf("expected 2 entries, got %d", rec.Count())
    }

    if !rec.ContainsMessage("hello") {
        t.Error("should contain 'hello'")
    }
}

Проверка уровня

go
func TestLogLevel(t *testing.T) {
    rec := dd.NewLoggerRecorder()
    // Примечание: Recorder разбирает уровень по временной метке ISO 8601,
    // формат времени DevelopmentConfig ("15:04:05.000") несовместим,
    // поэтому используем DefaultConfig и вручную задаём DEBUG.
    cfg := dd.DefaultConfig()
    cfg.Level = dd.LevelDebug
    logger, _ := rec.NewLogger(cfg)

    logger.Debug("debug")
    logger.Info("info")
    logger.Error("error")

    errors := rec.EntriesAtLevel(dd.LevelError)
    if len(errors) != 1 {
        t.Errorf("expected 1 error, got %d", len(errors))
    }

    debugs := rec.EntriesAtLevel(dd.LevelDebug)
    if len(debugs) != 1 {
        t.Errorf("expected 1 debug, got %d", len(debugs))
    }
}

Проверка структурированных полей

go
func TestStructuredLog(t *testing.T) {
    rec := dd.NewLoggerRecorder()
    logger, _ := rec.NewLogger()

    logger.InfoWith("user login",
        dd.String("user", "admin"),
        dd.String("ip", "192.168.1.1"),
    )

    if !rec.ContainsField("user") {
        t.Error("should contain 'user' field")
    }

    user := rec.GetFieldValue("user")
    if user != "admin" {
        t.Errorf("expected user=admin, got %v", user)
    }
}

Последняя запись лога

go
func TestLastEntry(t *testing.T) {
    rec := dd.NewLoggerRecorder()
    logger, _ := rec.NewLogger()

    logger.Info("first")
    logger.Error("second")

    last := rec.LastEntry()
    if last.Level != dd.LevelError {
        t.Errorf("expected Error level, got %v", last.Level)
    }
    if last.Message != "second" {
        t.Errorf("expected 'second', got %s", last.Message)
    }
}

LogEntry

Структура захваченной записи лога.

go
type LogEntry struct {
    Level     LogLevel
    Message   string
    Fields    []Field
    Timestamp time.Time
    Format    LogFormat
    RawOutput string
}

Следующие шаги