手機網(wǎng)站有哪些類型成都網(wǎng)絡(luò)推廣
快速開始
GoConvey是一個完全兼容官方Go Test的測試框架,一般來說這種第三方庫都比官方的功能要強大、更加易于使用、開發(fā)效率更高,閑話少說,先看一個example:
package utils
import (. "github.com/smartystreets/goconvey/convey""testing"
)func TestSpec(t *testing.T) {Convey("Given some integer with a starting value", t, func() {x := 1Convey("When the integer is incremented", func() {x++Convey("The value should be greater by one", func() {So(x, ShouldEqual, 2)})})})
}
看著復(fù)雜, 一層層的嵌套,如果你使用IDE的話你可以點到源碼里面看一下其方法注釋,其實已經(jīng)說的非常清楚了,這里摘取部分看一下:
// Convey is the method intended for use when declaring the scopes of
// a specification. Each scope has a description and a func() which may contain
// other calls to Convey(), Reset() or Should-style assertions. Convey calls can
// be nested as far as you see fit.
//
// IMPORTANT NOTE: The top-level Convey() within a Test method
// must conform to the following signature:
//
// Convey(description string, t *testing.T, action func())
//
// All other calls should look like this (no need to pass in *testing.T):
//
// Convey(description string, action func())
這個用法相對簡單了,Convey定義了一個局部的作用域,在這個作用域里面我們可以定義變量,調(diào)用方法,然后重復(fù)繼續(xù)這個操作,low-level的Convey會繼承top-level的變量。
了解之后,我們來擴展一下這個例子:
func TestSpec(t *testing.T) {Convey("Given some integer with a starting value", t, func() {x := 1y := 10Convey("When the integer is incremented", func() {x++Convey("The value should be greater by one", func() {So(x, ShouldEqual, 2)})})Convey("When x < y", func() {if x < y {x = x + ySo(x, ShouldBeGreaterThan, y)}})})
}
非常簡單,當(dāng)然這里我們并沒有測試任何函數(shù)或方法,下面咱們寫一個函數(shù)真正測試一下,假設(shè)有下面的方法:
func Div(a, b int) (int, error) {if b == 0 {return 0, errors.New("can not div zero")}return a / b, nil
}
使用GoConvey的話,測試代碼可以這么寫:
func TestDiv(t *testing.T) {const X = 10Convey("Normal Result", t, func() {res, err := Div(X, 2)So(res, ShouldEqual, 5)So(err, ShouldBeNil)Convey("Extend Scope", func() {res, err := Div(res, 2)So(res, ShouldEqual, 2)So(err, ShouldBeNil)})})Convey("Error Result", t, func() {res, err := Div(X, 0)So(res, ShouldEqual, 0)So(err, ShouldNotBeNil)})
}
有人可能會覺得這和官方的沒多大區(qū)別,相當(dāng)于多加了一個注釋,可以對每一個測試用例標識,但是不僅僅如此,這個庫還提供了大量增強的Assertions,可以非常方便的對字符串、slice、map結(jié)果進行斷言測試,具體的話可以查看一下文檔或者點進去看看源碼注釋,這些源碼注釋基本上已經(jīng)寫的非常清楚了。
Web UI
此外,框架還提供了一個Web端的UI界面,可以非常方便的查看測試覆蓋和運行情況,還可以自動運行測試,執(zhí)行g(shù)oconvey命令就可以啟動服務(wù),快試一試吧!(雖然說像Goland這樣的IDE也提供了GUI工具查看測試覆蓋率,但是這個更加方便)
另外,這個框架還提供了自定義Assertions的功能,使用起來也很方便,有一個通用的模板:
func should<do-something>(actual interface{}, expected ...interface{}) string {if <some-important-condition-is-met(actual, expected)> {return "" // empty string means the assertion passed}return "<some descriptive message detailing why the assertion failed...>"
}
舉個例子,這里定義一個試試:
func shouldNotGreatThan100(actual interface{}, expected ...interface{}) string {if actual.(int) > 100 {return "too big than 100"} else {return ""}
}
定義通用的邏輯
有時候測試會需要做一些準備工作,而且是重復(fù)的,比如說一些初始化操作,這時候就可以定義一個函數(shù)完成這件事,不必每次測試重復(fù)做,官方文檔里面舉了一個數(shù)據(jù)庫測試的例子,每次測試前開啟事務(wù),測試結(jié)束后回滾事務(wù),這里貼一下官方的example,大家看一下,很容易理解:
package main
import ("database/sql""testing"_ "github.com/lib/pq". "github.com/smartystreets/goconvey/convey"
)
func WithTransaction(db *sql.DB, f func(tx *sql.Tx)) func() {return func() {tx, err := db.Begin()So(err, ShouldBeNil)Reset(func() {/* Verify that the transaction is alive by executing a command */_, err := tx.Exec("SELECT 1")So(err, ShouldBeNil)tx.Rollback()})/* Here we invoke the actual test-closure and provide the transaction */f(tx)}
}
func TestUsers(t *testing.T) {db, err := sql.Open("postgres", "postgres://localhost?sslmode=disable")if err != nil {panic(err)}Convey("Given a user in the database", t, WithTransaction(db, func(tx *sql.Tx) {_, err := tx.Exec(`INSERT INTO "Users" ("id", "name") VALUES (1, 'Test User')`)So(err, ShouldBeNil)Convey("Attempting to retrieve the user should return the user", func() {var name stringdata := tx.QueryRow(`SELECT "name" FROM "Users" WHERE "id" = 1`)err = data.Scan(&name)So(err, ShouldBeNil)So(name, ShouldEqual, "Test User")})}))
}
/* Required table to run the test:
CREATE TABLE "public"."Users" ( "id" INTEGER NOT NULL UNIQUE, "name" CHARACTER VARYING( 2044 ) NOT NULL
);
*/