我想了解如何重构我的代码,例如使用mock.Mock来模拟db.Ping().我想先了解一下没有框架的概念.

下面是我要测试的代码:

func Connect() (*sql.DB, error) {

    db, err := sql.Open("mysql", "root:secret@tcp(s-maria-db)/s_db")

    if err != nil {
        return nil, err
    }

    for i := 0; i < 60; i++ {
        // I am hoping to mock this portion
        if err := db.Ping(); err == nil {
            break
        }
        time.Sleep(time.Second)
    }

    return db, nil
}

我try 了这个帖子How to mock a ping command,但这并没有真正回答这个问题.如果是这样,我就不理解解决方案,因为它适用于我的代码.

推荐答案

您需要使用一个单独的函数来执行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)
}

Database相关问答推荐

如何在 sql server 2005 中获取到数据库的详细连接列表?

Select 正确的数据库:MySQL 与Everything 其它数据库

将 .frm 和 .opt 文件导入 MySQL

Entity Framework:如何检测对数据库的外部更改

如何验证 SQLAlchemy ORM 中的列数据类型?

Zend 框架 - 为什么我应该使用数据映射器/Db_Table_Row?

我可以在 mysql 中的 select 语句上启动触发器吗?

MySQL JDBC Driver中cachePrepStmts和useServerPrepStmts有什么区别

将 XML 存储在数据库中是否不好?

是否有任何用于 NoSQL 数据库架构迁移的工具?

为什么有人需要内存数据库?

如何从 Django 中的 sql 模式生成数据模型?

如何在远程服务器上备份 MySQL 数据库?

在 Rails 中销毁/删除数据库

从 CSV 文件填充 Android 数据库?

为 PHPMyadmin DB 自动生成数据库图?

cURL 和 PHP 显示1

将查询限制为一条记录会提高性能吗

Apache Spark 的主键

清空数据库是什么意思?