为了账号安全,请及时绑定邮箱和手机立即绑定

如何使用 gorm 进行单元测试

如何使用 gorm 进行单元测试

Go
侃侃无极 2022-10-04 16:14:19
我是新来的和.在我的项目中,我正在使用和连接数据库。Gounit testGogormmysql我的查询是如何对我的代码进行单元测试的:main_test:package mainimport (    "log"    "os"    "testing"    "github.com/jinzhu/gorm"    _ "github.com/jinzhu/gorm/dialects/mysql")func TestinitDB(m *testing.M) {    dataSourceName := "root:@tcp(localhost:3306)/?parseTime=True"    db, err := gorm.Open("mysql", dataSourceName)    if err != nil {        log.Fatal("failed to connect database")    }    //db.Exec("CREATE DATABASE test")    db.LogMode(true)    db.Exec("USE test111")    os.Exit(m.Run())}请帮我写单元测试文件
查看完整描述

2 回答

?
慕哥6287543

TA贡献1831条经验 获得超10个赞

“如何进行单元测试”是一个非常广泛的问题,因为它取决于你想要测试什么。在您的示例中,您正在处理与数据库的远程连接,这通常是在单元测试中被嘲笑的东西。目前尚不清楚这是否是您要寻找的,也不是必需的。通过看到你使用不同的数据库,我希望其意图不是嘲笑。


首先看看这篇文章,它已经回答了你关于TestMain和打算如何工作的问题。testing.M


您的代码当前所做的(如果您的测试名称正确命名)是在其他测试周围添加一个方法来执行设置和拆卸,但是您没有任何其他测试来使用此设置和拆卸,因此您将获得结果。TestMainno tests to run


这不是你问题的一部分,但我建议尽量避免,直到你对测试Go代码有信心。使用和测试单独的单元可能更容易理解。你可以通过调用你的测试并让初始值设定项接受一个参数来实现几乎相同的事情。testing.Mtesting.TinitDB()


func initDB(dbToUse string) {

    // ...

    db.Exec("USE "+dbToUse)

}

然后,您将从主文件和测试中调用。您可以在 pkg.go.dev/testing 阅读有关 Go 的测试包的信息,您还可以在其中找到 和 之间的差异。initDB("test")initDB("test111")testing.Ttesting.M


下面是一个简短的示例,其中包含一些基本测试,这些测试不需要任何设置或拆卸,而是使用 代替 。testing.Ttesting.M


主要.go


package main


import "fmt"


func main() {

    fmt.Println(add(1, 2))

}


func add(a, b int) int {

    return a + b

}

main_test


package main


import "testing"


func TestAdd(t *testing.T) {

    t.Run("add 2 + 2", func(t *testing.T) {

        want := 4


        // Call the function you want to test.

        got := add(2, 2)


        // Assert that you got your expected response

        if got != want {

            t.Fail()

        }

    })

}

此测试将测试您的方法,并确保它在作为参数传递时返回正确的值。使用 是可选的,但它会为您创建一个子测试,这使得读取输出更容易一些。add2, 2t.Run


由于在包级别进行测试,因此,如果不以递归方式使用三点格式(包括每个包),则需要指定要测试的包。


若要运行上述示例中的测试,请指定包和详细输出。-v


$ go test ./ -v

=== RUN   TestAdd

=== RUN   TestAdd/add_2_+_2

--- PASS: TestAdd (0.00s)

    --- PASS: TestAdd/add_2_+_2 (0.00s)

PASS

ok      x       (cached)

围绕这个主题还有很多东西需要学习,比如测试框架和测试模式。例如,测试框架testify可以帮助您进行断言,并在测试失败时打印出漂亮的输出,并且表驱动的测试是Go中非常常见的模式。


您还在编写HTTP服务器,该服务器通常需要额外的测试设置才能正确测试。幸运的是,标准库中的包带有一个名为httptest的子包,它可以帮助您记录外部请求或为外部请求启动本地服务器。还可以通过使用手动构造的请求直接调用处理程序来测试处理程序。http


它看起来像这样。


func TestSomeHandler(t *testing.T) {

    // Create a request to pass to our handler. We don't have any query parameters for now, so we'll

    // pass 'nil' as the third parameter.

    req, err := http.NewRequest("GET", "/some-endpoint", nil)

    if err != nil {

        t.Fatal(err)

    }


    // We create a ResponseRecorder (which satisfies http.ResponseWriter) to record the response.

    rr := httptest.NewRecorder()

    handler := http.HandlerFunc(SomeHandler)


    // Our handlers satisfy http.Handler, so we can call their ServeHTTP method 

    // directly and pass in our Request and ResponseRecorder.

    handler.ServeHTTP(rr, req)


    // Check the status code is what we expect.

    if status := rr.Code; status != http.StatusOK {

        t.Errorf("handler returned wrong status code: got %v want %v",

            status, http.StatusOK)

    }

现在,测试一些代码。我们可以运行 init 方法,并使用响应记录器调用您的任何服务。


package main


import (

    "encoding/json"

    "net/http"

    "net/http/httptest"

    "testing"

)


func TestGetAllJobs(t *testing.T) {

    // Initialize the DB

    initDB("test111")


    req, err := http.NewRequest("GET", "/GetAllJobs", nil)

    if err != nil {

        t.Fatal(err)

    }


    rr := httptest.NewRecorder()

    handler := http.HandlerFunc(GetAllJobs)


    handler.ServeHTTP(rr, req)


    // Check the status code is what we expect.

    if status := rr.Code; status != http.StatusOK {

        t.Errorf("handler returned wrong status code: got %v want %v",

            status, http.StatusOK)

    }


    var response []Jobs

    if err := json.Unmarshal(rr.Body.Bytes(), &response); err != nil {

        t.Errorf("got invalid response, expected list of jobs, got: %v", rr.Body.String())

    }


    if len(response) < 1 {

        t.Errorf("expected at least 1 job, got %v", len(response))

    }


    for _, job := range response {

        if job.SourcePath == "" {

            t.Errorf("expected job id %d to  have a source path, was empty", job.JobID)

        }

    }

}


查看完整回答
反对 回复 2022-10-04
?
小怪兽爱吃肉

TA贡献1852条经验 获得超1个赞

你可以使用 go-sqlmock:


    package main


import (

    "database/sql"

    "regexp"

    "testing"


    "gopkg.in/DATA-DOG/go-sqlmock.v1"

    "gorm.io/driver/postgres"

    "gorm.io/gorm"

)


type Student struct {

    //*gorm.Model

    Name string

    ID string

}

type v2Suite struct {

    db      *gorm.DB

    mock    sqlmock.Sqlmock

    student Student

}


func TestGORMV2(t *testing.T) {

    s := &v2Suite{}

    var (

        db  *sql.DB

        err error

    )


    db, s.mock, err = sqlmock.New()

    if err != nil {

        t.Errorf("Failed to open mock sql db, got error: %v", err)

    }


    if db == nil {

        t.Error("mock db is null")

    }


    if s.mock == nil {

        t.Error("sqlmock is null")

    }


    dialector := postgres.New(postgres.Config{

        DSN:                  "sqlmock_db_0",

        DriverName:           "postgres",

        Conn:                 db,

        PreferSimpleProtocol: true,

    })

    s.db, err = gorm.Open(dialector, &gorm.Config{})

    if err != nil {

        t.Errorf("Failed to open gorm v2 db, got error: %v", err)

    }


    if s.db == nil {

        t.Error("gorm db is null")

    }


    s.student = Student{

        ID:   "123456",

        Name: "Test 1",

    }


    defer db.Close()


    s.mock.MatchExpectationsInOrder(false)

    s.mock.ExpectBegin()


    s.mock.ExpectQuery(regexp.QuoteMeta(

        `INSERT INTO "students" ("id","name")

                    VALUES ($1,$2) RETURNING "students"."id"`)).

    WithArgs(s.student.ID, s.student.Name).

    WillReturnRows(sqlmock.NewRows([]string{"id"}).

            AddRow(s.student.ID))


    s.mock.ExpectCommit()


    if err = s.db.Create(&s.student).Error; err != nil {

        t.Errorf("Failed to insert to gorm db, got error: %v", err)

    }


    err = s.mock.ExpectationsWereMet()

    if err != nil {

        t.Errorf("Failed to meet expectations, got error: %v", err)

    }

}



查看完整回答
反对 回复 2022-10-04
  • 2 回答
  • 0 关注
  • 352 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号