
Dmitri
08.06.2018
08:07:33
либо в метод, либо в пакет, либо в структуры пакета
но это уже вкусовщина
и все зависит от того, что твой пакет делает
если пакет - неотъемлемая часть приложения, можно его и синглтонами накормить, и свои кастомные зависимости напихать, и вообще

Google

Dmitri
08.06.2018
08:09:07
если пакет - библиотека, планируемая для реюза, так делать, конечно, не стоит

Александр
08.06.2018
08:09:13
ладно спасибо - я убег

Dmitri
08.06.2018
08:09:16
чем меньше в ней зависимостей, тем лучше
удачи тебе

Artem
08.06.2018
08:13:09

FRD Official - Dmitriy
08.06.2018
08:49:26

Artem
08.06.2018
08:49:39
это уже будет не юнит, а интеграционка

FRD Official - Dmitriy
08.06.2018
08:51:40

Artem
08.06.2018
08:52:51
В интеграционке мне кейсы недоступности базы в разные моменты воссоздать тяжело, из серии начать транзакцию удалось, а коммит нет

FRD Official - Dmitriy
08.06.2018
09:01:10
Не тестируй в нем живость бд - не будет интеграционкой

Artem
08.06.2018
09:04:13
Кейсы аварийного поведения мне тяжело задавать в тестовой бд, а мне надо проверить что во в любом случае данные не будут утеряны

Dmitri
08.06.2018
09:15:35
есть мнение, что это концептуально слабовозможно... доказательства будут лежать больше в математической плоскости

Google

Dmitri
08.06.2018
09:17:15
как бы, юнит - это такая штука, которая проверяет корректность кода. Ну, т.е. проверяет, насколько это возможно, факт того, что код делает ровно то, что обещал в неаварийных условиях работы, т.е. проверка, если угодно, на "соответствие контракту"
в случае "уронить соединение посреди транзакции" вам никто и ничего гарантировать не сможет
ну и, собственно, достаточно странный подход
ваш код либо завершил транзакцию, т.е. получил гарантию сохранности/консистентности данных со стороны БД, либо не смог, т.е. получил гарантию отсутствия изменений с момента старта транзакции со стороны БД
случай обрыва связи посреди транзакции - это ровно второй случай, и он, если честно, со стороны приложения проверке не подлежит, не та область ответственности


Artem
08.06.2018
09:23:51
Ну мне надо проверить что в случае отказа базы, он в файл запишет данные которые затем можно будет восстановить.
Сам клиент коннекта имеет возможность вернуть еррор при выполнение транзакции.
как бы, юнит - это такая штука, которая проверяет корректность кода. Ну, т.е. проверяет, насколько это возможно, факт того, что код делает ровно то, что обещал в неаварийных условиях работы, т.е. проверка, если угодно, на "соответствие контракту"
Тут не согласен, юнит может проверять не только success путь. Но краевые и аварийные значения.

FRD Official - Dmitriy
08.06.2018
09:28:10

Dmitri
08.06.2018
09:29:50
для второго достаточно запустить ровно то же самое без наличия соединения с базой
а эмулировать дроп коннекта посредине - это уже патч бд-коннекта с отсутствием гарантии идентичности поведения патченного бд-коннекта и непатченного бд-коннекта
ну, т.е. ересь получается


Artem
08.06.2018
09:33:02
Ну попытка тестирования в лоб заключалась в
type dbSqlInterface interface {
Begin() (transactionInterface, error)
Exec(query string, args ...interface{}) (sql.Result, error)
Ping() error
SetConnMaxLifetime(duration time.Duration)
}
type transactionInterface interface {
Exec(query string, args ...interface{}) (sql.Result, error)
Rollback() error
Commit() error
}

Dmitri
08.06.2018
09:34:32
вы аппаратные проблемы все равно на уровне юнит-тестирования не смоделируете
а значит не стоит и пытаться

Artem
08.06.2018
09:35:21
я эмулирую различный возврат фунций, ошибка не ошибка
выше представленный интерфейс хорошо работает, проверяет то что надо, но
реальный конект -
Begin() (*sql.Tx, error)
и вот этот один шаг, до решения всех моих проблем, все навернул
хотя и *sql.Tx реализует transactionInterface

Google

Artem
08.06.2018
09:38:24
и тут момент, даже не о моке конкретно базы, а что если автор пакета не завязал возрат на интерфейс, тестирование может сильно усложнится

Dmitri
08.06.2018
09:43:22
дело в том, что тестировать проблему с БД между sql.Begin() и sql.Commit() смысла нет
если где-то между произошел дроп соединения с базой, sql.Commit() зафейлится
а все, что вы писали между - откатится
т.е. смысла тестировать ЭТО - нет

Artem
08.06.2018
09:45:28
Даже если так, я не могу подменить sql.Commit() и проверять ошибку только в нем

Dmitri
08.06.2018
09:45:46
на уровне вашего приложения все, что происходит между sql.Tx.Query() и получением *sql.Result - черный ящик
и зачем проверять в нем ошибку?
вы не на том уровне. На уровне вашего приложения ситуация ошибки драйвера sql, мягко говоря, не существует
если вы, конечно, не пишете драйвер БД

Artem
08.06.2018
09:47:36
На уровне кода фунция, коммит имеет возможность вернуть ошибку

Artem
08.06.2018
09:47:59
-> значит этот кейс расматривается как поведение

Dmitri
08.06.2018
09:48:07
для того, чтобы она вернула ошибку, можно тупо не поднимать коннект к базе вообще

Artem
08.06.2018
09:48:43
тогда и пинг, и бегин вернут ошибку

Dmitri
08.06.2018
09:49:02
вы можете сделать реализацию интерфейса sql.Tx, которая будет на Commit возвращать тупо ошибку
а остальные - нет

Artem
08.06.2018
09:49:13
я сделал

Dmitri
08.06.2018
09:49:34
в ситуации дропа коннекта к базе вас интересует исключительно один фактор: коммит вернул ошибку
причем детали ошибки вас не интересуют, от слова "вообще"

Google

Artem
08.06.2018
09:49:52
все верно
посмотрите код выше, Begin() (*sql.Tx, error) а мне для подмены надо сделать Begin() (transactionInterface, error)
*sql.Tx реализует transactionInterface

Dmitri
08.06.2018
09:50:36
ну так вот в чем вопрос: в чем суть юнит-тестирования
sql.Tx - интерфейс же?

Artem
08.06.2018
09:51:24
неа
// Tx is an in-progress database transaction.
//
// A transaction must end with a call to Commit or Rollback.
//
// After a call to Commit or Rollback, all operations on the
// transaction fail with ErrTxDone.
//
// The statements prepared for a transaction by calling
// the transaction's Prepare or Stmt methods are closed
// by the call to Commit or Rollback.
type Tx struct {
db *DB

Dmitri
08.06.2018
09:51:55
не, структура, уговорил

Artem
08.06.2018
09:52:05
из .../go/1.10.1/libexec/src/database/sql/sql.go

Dmitri
08.06.2018
09:52:54
ну тогда нужно реализовывать sql-драйвер

Admin
ERROR: S client not available

Dmitri
08.06.2018
09:54:54
go-sql-driver реализовывает интерфейс же

Artem
08.06.2018
09:54:58
я всеравно же упрусь в контракт Begin() (*sql.Tx, error)

Dmitri
08.06.2018
09:56:27
неа
import(
_ "github.com/lib/pq"
)
а в lib/pq вот такая вещь:
func init() {
sql.Register("postgres", &Driver{})
}
а вот уже Driver реализовывает интерфейс
ща поищу, куда там можно вклиниться
https://golang.org/src/database/sql/doc.txt

Artem
08.06.2018
10:03:28
Буду где то там копать, спасибо

Dmitri
08.06.2018
10:04:28
https://golang.org/pkg/database/sql/driver/

Google

Dmitri
08.06.2018
10:04:50
во, вот тут написано defines interfaces to be implemented by database drivers as used by package sql
т.е. здесь интерфейсы для всего лоу-левела под sql
вооот же ОНО:
https://golang.org/pkg/database/sql/driver/#Tx
т.е. в драйвере есть driver.Tx, который интерфейс
а в момент sql.Register в сервис-провайдере регистрируется нужный тип
в момент db.Open - создается его инстанс, и дальше sql рулит пулом этих инстансов
а в sql.Tx в момент инициализации соединения суется реализация driver.Tx
они реализовывают один и тот же интерфейс, поэтому там просто подсовываются указатели на методы

Artem
08.06.2018
10:10:07
Я начинал с sql.DB как с входной точки

Dmitri
08.06.2018
10:10:10
т.е. для ваших особо изощренных тестирований - пишите драйвер)
а она юзает sql/driver.Driver под капотом

Artem
08.06.2018
10:11:20
Который умеет только Open(name string) (Conn, error) ?

FRD Official - Dmitriy
08.06.2018
10:11:27
Все украдено до нас https://github.com/DATA-DOG/go-sqlmock

Dmitri
08.06.2018
10:11:48
а этот Conn - это интерфейс
а скулю нужно рулить пулом этих соединений

Artem
08.06.2018
10:12:44

FRD Official - Dmitriy
08.06.2018
10:13:15

Dmitri
08.06.2018
10:14:53

Artem
08.06.2018
10:17:54
тут вот не до конца понял
мы же упремся в
func (m *testSql) Begin() (*sql.Tx, error)
где не сможем вернуть - type testTransaction struct{
sql.Tx
}

Dmitri
08.06.2018
10:19:41
а зачем тебе возвращать testTransaction?