您需要使用一个单独的函数来执行ping操作,并且它需要接受一个接口,这样您就可以有条件地传入真实的*sql.DB
或模拟的.这是因为您不能重写 struct 上的方法.
// Connect opens a connection to the database.
func Connect() (*sql.DB, error) {
return sql.Open("mysql", "root:secret@tcp(s-maria-db)/s_db")
}
// Pinger defines an interface for pinging.
type Pinger interface {
Ping() error
}
// Ping attempts to ping the database, trying several times before failing.
func Ping(p Pinger) error {
const maxAttempts = 60
var err error
for i := 0; i < maxAttempts; i++ {
if err = p.Ping(); err == nil {
return nil
}
if i < maxAttempts - 1 {
time.Sleep(time.Second)
}
}
return err
}
func main() {
if err := run(); err != nil {
log.Fatal(err)
}
}
func run() error {
db, err := Connect()
if err != nil {
return fmt.Errorf("connecting to db: %w", err)
}
defer db.Close()
if err = Ping(db); err != nil {
return fmt.Errorf("pinging db: %w", err)
}
...
}
type mockDB struct {
mock.Mock
}
func (m *mockDB) Ping() error {
args := m.Called()
return args.Error(0)
}
func TestPing(t *testing.T) {
db := &mockDB{}
db.On("Ping").Return(...)
err := Ping(db)
...
db.AssertExpectations(t)
}