慕哥6287543
“如何进行单元测试”是一个非常广泛的问题,因为它取决于你想要测试什么。在您的示例中,您正在处理与数据库的远程连接,这通常是在单元测试中被嘲笑的东西。目前尚不清楚这是否是您要寻找的,也不是必需的。通过看到你使用不同的数据库,我希望其意图不是嘲笑。首先看看这篇文章,它已经回答了你关于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主要.gopackage mainimport "fmt"func main() { fmt.Println(add(1, 2))}func add(a, b int) int { return a + b}main_testpackage mainimport "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)PASSok 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 mainimport ( "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) } }}
小怪兽爱吃肉
你可以使用 go-sqlmock: package mainimport ( "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) }}