TDD Конструкторы Голанг - PullRequest
       8

TDD Конструкторы Голанг

0 голосов
/ 16 ноября 2018

Несмотря на то, что есть несколько постов по этому вопросу, я не нашел ни одного с большим содержанием. Так что, надеюсь, несколько человек поделятся своим мнением по этому поводу.

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

Например:

type DB struct {
    conn *sql.DB
}

func NewDB(URL string) (*DB, err) {
    conn, err := sql.Open("postgres", URL)
    if err != nil {
        return nil, err
    }
}

Я знаю, что мог бы передать sql-соединение в NewDB или непосредственно в структуру и назначить его интерфейсу, который имеет все необходимые мне методы, и это было бы легко проверить. Но где-то я собираюсь подключиться. Единственный способ проверить, что мне удалось найти, это ...

var sqlOpen = sql.Open
func CreateDB() *DB {
    conn, err := sqlOpen("postgres", "url...")
    if err != nil {
         log.Fatal(err)
    }

    dataBase = DB{
        conn: conn
    }
}

Затем в тесте вы заменяете функцию sqlOpen чем-то, что возвращает функцию с такой же сигнатурой, которая выдаст ошибку для одного теста и не выдаст ошибку для другого. Но это похоже на хак, особенно если вы делаете это для нескольких функций в одном файле. Есть ли способ лучше? База кода, с которой я работаю, имеет множество функций в пакетах и ​​сетевых подключениях. Поскольку я изо всех сил пытаюсь протестировать вещи в чистом виде, это отталкивает меня от TDD.

1 Ответ

0 голосов
/ 16 ноября 2018

Типичное бизнес-приложение имеет МНОГО логики в запросах. Мы значительно уменьшаем охват тестированием и оставляем место для ошибок регрессии, если они не тестируются. Таким образом, издевательство над хранилищами БД - не лучший вариант. Вместо этого мы можем смоделировать саму базу данных и проверить, как мы работаем с ней на уровне SQL.

Ниже приведен пример кода с использованием DATA-DOG / go-sqlmock , но могут существовать и другие библиотеки, которые могут макетировать базы данных sql.

Прежде всего, нам нужно внедрить соединение SQL в наш код. GO sql connection - вводящее в заблуждение имя, и это фактически пул соединений, а не просто соединение с одной БД. Вот почему имеет смысл создать один *sql.DB в корне вашей композиции и повторно использовать в коде, даже если вы не пишете тесты.

Пример ниже показывает, как макетировать веб-сервис.

В начале нам нужно создать новый обработчик с внедренным соединением:

// New creates new handler
func New(db *sql.DB) http.Handler {
    return &handler{
        db:     db,
    }
}

Код обработчика:

type handler struct {
    db     *sql.DB
}

func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  // some code that loads person name from database using id
}

Модульный тест того кода, который имитирует БД. Он использует stretchr / testify для утверждений:

func TestHandler(t *testing.T) {
    db, sqlMock, _ := sqlmock.New()
    rows := sqlmock.NewRows([]string{"name"}).AddRow("John")
    // regex is used to match query
    // assert that we execute SQL statement with parameter and return data
    sqlMock.ExpectQuery(`select name from person where id \= \?`).WithArgs(42).WillReturnRows(rows)
    defer db.Close()

    sut := mypackage.New(db)

    r, err := http.NewRequest(http.MethodGet, "https://example.com", nil)
    require.NoError(t, err, fmt.Sprintf("Failed to create request: %v", err))
    w := httptest.NewRecorder()

    sut.ServeHTTP(w, r)
    // make sure that all DB expectations were met 
    err = sqlMock.ExpectationsWereMet()
    assert.NoError(t, err)
    // other assertions that check DB data should be here 
    assert.Equal(t, http.StatusOK, w.Code)
}

Наш тест утверждает простой оператор SQL для БД. Но с go-sqlmock можно протестировать все операции CRUD и транзакции базы данных.

Тест выше имеет еще одно слабое место. Мы проверили, что наш оператор SQL выполняется из кода, но мы не проверяли, работает ли он с нашей реальной БД. Эта проблема не может быть решена с помощью модульных тестов. Единственное решение - интеграционное тестирование с реальной БД.

Мы сейчас в лучшем положении. Наша бизнес-логика уже проверена в модульных тестах. Нам не нужно создавать множество интеграционных тестов, чтобы охватить различные сценарии и параметры, вместо этого нам нужно иметь только один тест на запрос для проверки синтаксиса SQL и соответствия нашей схеме БД.

Счастливого тестирования!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...