成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專(zhuān)欄INFORMATION COLUMN

編寫(xiě)可測(cè)試的Go代碼

khlbat / 2700人閱讀

摘要:功能測(cè)試函數(shù)功能測(cè)試函數(shù)需要接收類(lèi)型的單一參數(shù),類(lèi)型用來(lái)管理測(cè)試狀態(tài)和支持格式化的測(cè)試日志。測(cè)試函數(shù)的相關(guān)說(shuō)明,可以通過(guò)來(lái)查看幫助文檔。下面是一個(gè)例子被測(cè)試的進(jìn)程退出函數(shù)測(cè)試進(jìn)程退出函數(shù)的測(cè)試函數(shù)參考資料原文鏈接

原文鏈接:http://tabalt.net/blog/golang...

Golang作為一門(mén)標(biāo)榜工程化的語(yǔ)言,提供了非常簡(jiǎn)便、實(shí)用的編寫(xiě)單元測(cè)試的能力。本文通過(guò)Golang源碼包中的用法,來(lái)學(xué)習(xí)在實(shí)際項(xiàng)目中如何編寫(xiě)可測(cè)試的Go代碼。

第一個(gè)測(cè)試 “Hello Test!”

首先,在我們$GOPATH/src目錄下創(chuàng)建hello目錄,作為本文涉及到的所有示例代碼的根目錄。

然后,新建名為hello.go的文件,定義一個(gè)函數(shù)hello(),功能是返回一個(gè)由若干單詞拼接成句子:

package hello

func hello() string {
    words := []string{"hello", "func", "in", "package", "hello"}
    wl := len(words)

    sentence := ""
    for key, word := range words {
        sentence += word
        if key < wl-1 {
            sentence += " "
        } else {
            sentence += "."
        }
    }
    return sentence
}

接著,新建名為hello_test.go的文件,填入如下內(nèi)容:

package hello

import (
    "fmt"
    "testing"
)

func TestHello(t *testing.T) {
    got := hello()
    expect := "hello func in package hello."

    if got != expect {
        t.Errorf("got [%s] expected [%s]", got, expect)
    }
}

func BenchmarkHello(b *testing.B) {
    for i := 0; i < b.N; i++ {
        hello()
    }
}

func ExampleHello() {
    hl := hello()
    fmt.Println(hl)
    // Output: hello func in package hello.
}

最后,打開(kāi)終端,進(jìn)入hello目錄,輸入go test命令并回車(chē),可以看到如下輸出:

PASS
ok      hello  0.007s
編寫(xiě)測(cè)試代碼

Golang的測(cè)試代碼位于某個(gè)包的源代碼中名稱(chēng)以_test.go結(jié)尾的源文件里,測(cè)試代碼包含測(cè)試函數(shù)、測(cè)試輔助代碼和示例函數(shù);測(cè)試函數(shù)有以Test開(kāi)頭的功能測(cè)試函數(shù)和以Benchmark開(kāi)頭的性能測(cè)試函數(shù)兩種,測(cè)試輔助代碼是為測(cè)試函數(shù)服務(wù)的公共函數(shù)、初始化函數(shù)、測(cè)試數(shù)據(jù)等,示例函數(shù)則是以Example開(kāi)頭的說(shuō)明被測(cè)試函數(shù)用法的函數(shù)。

大部分情況下,測(cè)試代碼是作為某個(gè)包的一部分,意味著它可以訪問(wèn)包中不可導(dǎo)出的元素。但在有需要的時(shí)候(如避免循環(huán)依賴(lài))也可以修改測(cè)試文件的包名,如package hello的測(cè)試文件,包名可以設(shè)為package hello_test

功能測(cè)試函數(shù)

功能測(cè)試函數(shù)需要接收*testing.T類(lèi)型的單一參數(shù)t,testing.T 類(lèi)型用來(lái)管理測(cè)試狀態(tài)和支持格式化的測(cè)試日志。測(cè)試日志在測(cè)試執(zhí)行過(guò)程中積累起來(lái),完成后輸出到標(biāo)準(zhǔn)錯(cuò)誤輸出。

下面是從Go標(biāo)準(zhǔn)庫(kù)摘抄的 testing.T類(lèi)型的常用方法的用法:

測(cè)試函數(shù)中的某條測(cè)試用例執(zhí)行結(jié)果與預(yù)期不符時(shí),調(diào)用t.Error()或t.Errorf()方法記錄日志并標(biāo)記測(cè)試失敗

# /usr/local/go/src/bytes/compare_test.go
func TestCompareIdenticalSlice(t *testing.T) {
    var b = []byte("Hello Gophers!")
    if Compare(b, b) != 0 {
        t.Error("b != b")
    }
    if Compare(b, b[:1]) != 1 {
        t.Error("b > b[:1] failed")
    }
}

使用t.Fatal()和t.Fatalf()方法,在某條測(cè)試用例失敗后就跳出該測(cè)試函數(shù)

# /usr/local/go/src/bytes/reader_test.go
func TestReadAfterBigSeek(t *testing.T) {
    r := NewReader([]byte("0123456789"))
    if _, err := r.Seek(1<<31+5, os.SEEK_SET); err != nil {
        t.Fatal(err)
    }
    if n, err := r.Read(make([]byte, 10)); n != 0 || err != io.EOF {
        t.Errorf("Read = %d, %v; want 0, EOF", n, err)
    }
}

使用t.Skip()和t.Skipf()方法,跳過(guò)某條測(cè)試用例的執(zhí)行

# /usr/local/go/src/archive/zip/zip_test.go
func TestZip64(t *testing.T) {
    if testing.Short() {
        t.Skip("slow test; skipping")
    }
    const size = 1 << 32 // before the "END
" part
    buf := testZip64(t, size)
    testZip64DirectoryRecordLength(buf, t)
}

執(zhí)行測(cè)試用例的過(guò)程中通過(guò)t.Log()和t.Logf()記錄日志

# /usr/local/go/src/regexp/exec_test.go
func TestFowler(t *testing.T) {
    files, err := filepath.Glob("testdata/*.dat")
    if err != nil {
        t.Fatal(err)
    }
    for _, file := range files {
        t.Log(file)
        testFowler(t, file)
    }
}

使用t.Parallel()標(biāo)記需要并發(fā)執(zhí)行的測(cè)試函數(shù)

# /usr/local/go/src/runtime/stack_test.go
func TestStackGrowth(t *testing.T) {
    t.Parallel()
    var wg sync.WaitGroup

    // in a normal goroutine
    wg.Add(1)
    go func() {
        defer wg.Done()
        growStack()
    }()
    wg.Wait()

    // ...
}

性能測(cè)試函數(shù)

性能測(cè)試函數(shù)需要接收*testing.B類(lèi)型的單一參數(shù)b,性能測(cè)試函數(shù)中需要循環(huán)b.N次調(diào)用被測(cè)函數(shù)。testing.B 類(lèi)型用來(lái)管理測(cè)試時(shí)間和迭代運(yùn)行次數(shù),也支持和testing.T相同的方式管理測(cè)試狀態(tài)和格式化的測(cè)試日志,不一樣的是testing.B的日志總是會(huì)輸出。

下面是從Go標(biāo)準(zhǔn)庫(kù)摘抄的 testing.B類(lèi)型的常用方法的用法:

在函數(shù)中調(diào)用t.ReportAllocs(),啟用內(nèi)存使用分析

# /usr/local/go/src/bufio/bufio_test.go
func BenchmarkWriterFlush(b *testing.B) {
    b.ReportAllocs()
    bw := NewWriter(ioutil.Discard)
    str := strings.Repeat("x", 50)
    for i := 0; i < b.N; i++ {
        bw.WriteString(str)
        bw.Flush()
    }
}

通過(guò) b.StopTimer()、b.ResetTimer()、b.StartTimer()來(lái)停止、重置、啟動(dòng) 時(shí)間經(jīng)過(guò)和內(nèi)存分配計(jì)數(shù)

# /usr/local/go/src/fmt/scan_test.go
func BenchmarkScanInts(b *testing.B) {
    b.ResetTimer()
    ints := makeInts(intCount)
    var r RecursiveInt
    for i := b.N - 1; i >= 0; i-- {
        buf := bytes.NewBuffer(ints)
        b.StartTimer()
        scanInts(&r, buf)
        b.StopTimer()
    }
}

調(diào)用b.SetBytes()記錄在一個(gè)操作中處理的字節(jié)數(shù)

# /usr/local/go/src/testing/benchmark.go
func BenchmarkFields(b *testing.B) {
    b.SetBytes(int64(len(fieldsInput)))
    for i := 0; i < b.N; i++ {
        Fields(fieldsInput)
    }
}

通過(guò)b.RunParallel()方法和 *testing.PB類(lèi)型的Next()方法來(lái)并發(fā)執(zhí)行被測(cè)對(duì)象

# /usr/local/go/src/sync/atomic/value_test.go
func BenchmarkValueRead(b *testing.B) {
    var v Value
    v.Store(new(int))
    b.RunParallel(func(pb *testing.PB) {
        for pb.Next() {
            x := v.Load().(*int)
            if *x != 0 {
                b.Fatalf("wrong value: got %v, want 0", *x)
            }
        }
    })
}

測(cè)試輔助代碼

測(cè)試輔助代碼是編寫(xiě)測(cè)試代碼過(guò)程中因代碼重用和代碼質(zhì)量考慮而產(chǎn)生的。主要包括如下方面:

引入依賴(lài)的外部包,如每個(gè)測(cè)試文件都需要的 testing 包等:

# /usr/local/go/src/log/log_test.go:
import (
    "bytes"
    "fmt"
    "os"
    "regexp"
    "strings"
    "testing"
    "time"
)

定義多次用到的常量和變量,測(cè)試用例數(shù)據(jù)等:

# /usr/local/go/src/log/log_test.go:
const (
    Rdate         = `[0-9][0-9][0-9][0-9]/[0-9][0-9]/[0-9][0-9]`
    Rtime         = `[0-9][0-9]:[0-9][0-9]:[0-9][0-9]`
    Rmicroseconds = `.[0-9][0-9][0-9][0-9][0-9][0-9]`
    Rline         = `(57|59):` // must update if the calls to l.Printf / l.Print below move
    Rlongfile     = `.*/[A-Za-z0-9_-]+.go:` + Rline
    Rshortfile    = `[A-Za-z0-9_-]+.go:` + Rline
)

// ...

var tests = []tester{
    // individual pieces:
    {0, "", ""},
    {0, "XXX", "XXX"},
    {Ldate, "", Rdate + " "},
    {Ltime, "", Rtime + " "},
    {Ltime | Lmicroseconds, "", Rtime + Rmicroseconds + " "},
    {Lmicroseconds, "", Rtime + Rmicroseconds + " "}, // microsec implies time
    {Llongfile, "", Rlongfile + " "},
    {Lshortfile, "", Rshortfile + " "},
    {Llongfile | Lshortfile, "", Rshortfile + " "}, // shortfile overrides longfile
    // everything at once:
    {Ldate | Ltime | Lmicroseconds | Llongfile, "XXX", "XXX" + Rdate + " " + Rtime + Rmicroseconds + " " + Rlongfile + " "},
    {Ldate | Ltime | Lmicroseconds | Lshortfile, "XXX", "XXX" + Rdate + " " + Rtime + Rmicroseconds + " " + Rshortfile + " "},
}

和普通的Golang源代碼一樣,測(cè)試代碼中也能定義init函數(shù),init函數(shù)會(huì)在引入外部包、定義常量、聲明變量之后被自動(dòng)調(diào)用,可以在init函數(shù)里編寫(xiě)測(cè)試相關(guān)的初始化代碼。

# /usr/local/go/src/bytes/buffer_test.go
func init() {
    testBytes = make([]byte, N)
    for i := 0; i < N; i++ {
        testBytes[i] = "a" + byte(i%26)
    }
    data = string(testBytes)
}

封裝測(cè)試專(zhuān)用的公共函數(shù),抽象測(cè)試專(zhuān)用的結(jié)構(gòu)體等:

# /usr/local/go/src/log/log_test.go:
type tester struct {
    flag    int
    prefix  string
    pattern string // regexp that log output must match; we add ^ and expected_text$ always
}

// ...

func testPrint(t *testing.T, flag int, prefix string, pattern string, useFormat bool) {
    // ...
}

示例函數(shù)

示例函數(shù)無(wú)需接收參數(shù),但需要使用注釋的 Output: 標(biāo)記說(shuō)明示例函數(shù)的輸出值,未指定Output:標(biāo)記或輸出值為空的示例函數(shù)不會(huì)被執(zhí)行。

示例函數(shù)需要?dú)w屬于某個(gè) 包/函數(shù)/類(lèi)型/類(lèi)型 的方法,具體命名規(guī)則如下:

func Example() { ... }      # 包的示例函數(shù)
func ExampleF() { ... }     # 函數(shù)F的示例函數(shù)
func ExampleT() { ... }     # 類(lèi)型T的示例函數(shù)
func ExampleT_M() { ... }   # 類(lèi)型T的M方法的示例函數(shù)

# 多示例函數(shù) 需要跟下劃線(xiàn)加小寫(xiě)字母開(kāi)頭的后綴
func Example_suffix() { ... }
func ExampleF_suffix() { ... }
func ExampleT_suffix() { ... }
func ExampleT_M_suffix() { ... }

go doc 工具會(huì)解析示例函數(shù)的函數(shù)體作為對(duì)應(yīng) 包/函數(shù)/類(lèi)型/類(lèi)型的方法 的用法。

測(cè)試函數(shù)的相關(guān)說(shuō)明,可以通過(guò)go help testfunc來(lái)查看幫助文檔。

使用 go test 工具

Golang中通過(guò)命令行工具go test來(lái)執(zhí)行測(cè)試代碼,打開(kāi)shell終端,進(jìn)入需要測(cè)試的包所在的目錄執(zhí)行 go test,或者直接執(zhí)行go test $pkg_name_in_gopath即可對(duì)指定的包執(zhí)行測(cè)試。

通過(guò)形如go test github.com/tabalt/...的命令可以執(zhí)行$GOPATH/github.com/tabalt/目錄下所有的項(xiàng)目的測(cè)試。go test std命令則可以執(zhí)行Golang標(biāo)準(zhǔn)庫(kù)的所有測(cè)試。

如果想查看執(zhí)行了哪些測(cè)試函數(shù)及函數(shù)的執(zhí)行結(jié)果,可以使用-v參數(shù):

[tabalt@localhost hello] go test -v
=== RUN   TestHello
--- PASS: TestHello (0.00s)
=== RUN   ExampleHello
--- PASS: ExampleHello (0.00s)
PASS
ok      hello  0.006s

假設(shè)我們有很多功能測(cè)試函數(shù),但某次測(cè)試只想執(zhí)行其中的某一些,可以通過(guò)-run參數(shù),使用正則表達(dá)式來(lái)匹配要執(zhí)行的功能測(cè)試函數(shù)名。如下面指定參數(shù)后,功能測(cè)試函數(shù)TestHello不會(huì)執(zhí)行到。

[tabalt@localhost hello] go test -v -run=xxx
PASS
ok      hello  0.006s

性能測(cè)試函數(shù)默認(rèn)并不會(huì)執(zhí)行,需要添加-bench參數(shù),并指定匹配性能測(cè)試函數(shù)名的正則表達(dá)式;例如,想要執(zhí)行某個(gè)包中所有的性能測(cè)試函數(shù)可以添加參數(shù)-bench .-bench=.

[tabalt@localhost hello] go test -bench=.
PASS
BenchmarkHello-8     2000000           657 ns/op
ok      hello  1.993s

想要查看性能測(cè)試時(shí)的內(nèi)存情況,可以再添加參數(shù)-benchmem

[tabalt@localhost hello] go test -bench=. -benchmem
PASS
BenchmarkHello-8     2000000           666 ns/op         208 B/op          9 allocs/op
ok      hello  2.014s

參數(shù)-cover可以用來(lái)查看我們編寫(xiě)的測(cè)試對(duì)代碼的覆蓋率:

[tabalt@localhost hello] go test -cover
PASS
coverage: 100.0% of statements
ok      hello  0.006s

詳細(xì)的覆蓋率信息,可以通過(guò)-coverprofile輸出到文件,并使用go tool cover來(lái)查看,用法請(qǐng)參考go tool cover -help

更多go test命令的參數(shù)及用法,可以通過(guò)go help testflag來(lái)查看幫助文檔。

高級(jí)測(cè)試技術(shù)

IO相關(guān)測(cè)試

testing/iotest包中實(shí)現(xiàn)了常用的出錯(cuò)的Reader和Writer,可供我們?cè)趇o相關(guān)的測(cè)試中使用。主要有:

觸發(fā)數(shù)據(jù)錯(cuò)誤dataErrReader,通過(guò)DataErrReader()函數(shù)創(chuàng)建

讀取一半內(nèi)容的halfReader,通過(guò)HalfReader()函數(shù)創(chuàng)建

讀取一個(gè)byte的oneByteReader,通過(guò)OneByteReader()函數(shù)創(chuàng)建

觸發(fā)超時(shí)錯(cuò)誤的timeoutReader,通過(guò)TimeoutReader()函數(shù)創(chuàng)建

寫(xiě)入指定位數(shù)內(nèi)容后停止的truncateWriter,通過(guò)TruncateWriter()函數(shù)創(chuàng)建

讀取時(shí)記錄日志的readLogger,通過(guò)NewReadLogger()函數(shù)創(chuàng)建

寫(xiě)入時(shí)記錄日志的writeLogger,通過(guò)NewWriteLogger()函數(shù)創(chuàng)建

黑盒測(cè)試

testing/quick包實(shí)現(xiàn)了幫助黑盒測(cè)試的實(shí)用函數(shù) Check和CheckEqual。

Check函數(shù)的第1個(gè)參數(shù)是要測(cè)試的只返回bool值的黑盒函數(shù)f,Check會(huì)為f的每個(gè)參數(shù)設(shè)置任意值并多次調(diào)用,如果f返回false,Check函數(shù)會(huì)返回錯(cuò)誤值 *CheckError。Check函數(shù)的第2個(gè)參數(shù) 可以指定一個(gè)quick.Config類(lèi)型的config,傳nil則會(huì)默認(rèn)使用quick.defaultConfig。quick.Config結(jié)構(gòu)體包含了測(cè)試運(yùn)行的選項(xiàng)。

# /usr/local/go/src/math/big/int_test.go
func checkMul(a, b []byte) bool {
    var x, y, z1 Int
    x.SetBytes(a)
    y.SetBytes(b)
    z1.Mul(&x, &y)

    var z2 Int
    z2.SetBytes(mulBytes(a, b))

    return z1.Cmp(&z2) == 0
}

func TestMul(t *testing.T) {
    if err := quick.Check(checkMul, nil); err != nil {
        t.Error(err)
    }
}

CheckEqual函數(shù)是比較給定的兩個(gè)黑盒函數(shù)是否相等,函數(shù)原型如下:

func CheckEqual(f, g interface{}, config *Config) (err error)

HTTP測(cè)試

net/http/httptest包提供了HTTP相關(guān)代碼的工具,我們的測(cè)試代碼中可以創(chuàng)建一個(gè)臨時(shí)的httptest.Server來(lái)測(cè)試發(fā)送HTTP請(qǐng)求的代碼:

ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintln(w, "Hello, client")
}))
defer ts.Close()

res, err := http.Get(ts.URL)
if err != nil {
    log.Fatal(err)
}

greeting, err := ioutil.ReadAll(res.Body)
res.Body.Close()
if err != nil {
    log.Fatal(err)
}

fmt.Printf("%s", greeting)

還可以創(chuàng)建一個(gè)應(yīng)答的記錄器httptest.ResponseRecorder來(lái)檢測(cè)應(yīng)答的內(nèi)容:

handler := func(w http.ResponseWriter, r *http.Request) {
    http.Error(w, "something failed", http.StatusInternalServerError)
}

req, err := http.NewRequest("GET", "http://example.com/foo", nil)
if err != nil {
    log.Fatal(err)
}

w := httptest.NewRecorder()
handler(w, req)

fmt.Printf("%d - %s", w.Code, w.Body.String())

測(cè)試進(jìn)程操作行為

當(dāng)我們被測(cè)函數(shù)有操作進(jìn)程的行為,可以將被測(cè)程序作為一個(gè)子進(jìn)程執(zhí)行測(cè)試。下面是一個(gè)例子:

//被測(cè)試的進(jìn)程退出函數(shù)
func Crasher() {
    fmt.Println("Going down in flames!")
    os.Exit(1)
}

//測(cè)試進(jìn)程退出函數(shù)的測(cè)試函數(shù)
func TestCrasher(t *testing.T) {
    if os.Getenv("BE_CRASHER") == "1" {
        Crasher()
        return
    }
    cmd := exec.Command(os.Args[0], "-test.run=TestCrasher")
    cmd.Env = append(os.Environ(), "BE_CRASHER=1")
    err := cmd.Run()
    if e, ok := err.(*exec.ExitError); ok && !e.Success() {
        return
    }
    t.Fatalf("process ran with err %v, want exit status 1", err)
}
參考資料

https://talks.golang.org/2014...
https://golang.org/pkg/testing/
https://golang.org/pkg/testin...
https://golang.org/pkg/testin...
https://golang.org/pkg/net/ht...

原文鏈接:http://tabalt.net/blog/golang...

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/8738.html

相關(guān)文章

  • 撰寫(xiě)可測(cè)試的 JavaScript

    摘要:我們已經(jīng)準(zhǔn)備好經(jīng)歷一段痛苦的撰寫(xiě)單元測(cè)試的過(guò)程了,但最終我們能夠撰寫(xiě)可測(cè)試的。這種代碼是很容易進(jìn)行集成測(cè)試的,但幾乎不可能針對(duì)功能單元進(jìn)行單獨(dú)的測(cè)試。我們絕對(duì)可以寫(xiě)出集成測(cè)試的代碼,但我們應(yīng)該很難寫(xiě)出單元測(cè)試了。 轉(zhuǎn)自 勾三股四 - 撰寫(xiě)可測(cè)試的 JavaScript 這篇文章算是 A List Apart 系列文章中,包括滑動(dòng)門(mén)在內(nèi),令我印象最深刻的文章之一。最近有時(shí)間翻譯了一下,...

    Eminjannn 評(píng)論0 收藏0
  • 前端進(jìn)階之路: 前端架構(gòu)設(shè)計(jì)(3) - 測(cè)試核心

    摘要:而測(cè)試驅(qū)動(dòng)開(kāi)發(fā)技術(shù)并不只是單純的測(cè)試工作。需求向來(lái)就是軟件開(kāi)發(fā)過(guò)程中感覺(jué)最不好明確描述易變的東西。這里說(shuō)的需求不只是指用戶(hù)的需求,還包括對(duì)代碼 可能很多人和我一樣, 首次聽(tīng)到前端架構(gòu)這個(gè)詞, 第一反應(yīng)是: 前端還有架構(gòu)這一說(shuō)呢? 在后端開(kāi)發(fā)領(lǐng)域, 系統(tǒng)規(guī)劃和可擴(kuò)展性非常關(guān)鍵, 因此架構(gòu)師備受重視, 早在開(kāi)發(fā)工作啟動(dòng)之前, 他們就被邀請(qǐng)加入到項(xiàng)目中, 而且他們會(huì)跟客戶(hù)討論即將建成的平臺(tái)的...

    Karuru 評(píng)論0 收藏0
  • 前端進(jìn)階之路: 前端架構(gòu)設(shè)計(jì)(3) - 測(cè)試核心

    摘要:而測(cè)試驅(qū)動(dòng)開(kāi)發(fā)技術(shù)并不只是單純的測(cè)試工作。需求向來(lái)就是軟件開(kāi)發(fā)過(guò)程中感覺(jué)最不好明確描述易變的東西。這里說(shuō)的需求不只是指用戶(hù)的需求,還包括對(duì)代碼 可能很多人和我一樣, 首次聽(tīng)到前端架構(gòu)這個(gè)詞, 第一反應(yīng)是: 前端還有架構(gòu)這一說(shuō)呢? 在后端開(kāi)發(fā)領(lǐng)域, 系統(tǒng)規(guī)劃和可擴(kuò)展性非常關(guān)鍵, 因此架構(gòu)師備受重視, 早在開(kāi)發(fā)工作啟動(dòng)之前, 他們就被邀請(qǐng)加入到項(xiàng)目中, 而且他們會(huì)跟客戶(hù)討論即將建成的平臺(tái)的...

    宋華 評(píng)論0 收藏0
  • 基于 vue-upload-component 封裝一個(gè)圖片上傳組件

    摘要:預(yù)覽因?yàn)轫?xiàng)目是基于做的,本身就提供了的預(yù)覽組件,使用起來(lái)也簡(jiǎn)單,如果業(yè)務(wù)需求需要放大縮小,這個(gè)組件就不滿(mǎn)足了。 需求分析 業(yè)務(wù)要求,需要一個(gè)圖片上傳控件,需滿(mǎn)足 多圖上傳 點(diǎn)擊預(yù)覽 圖片前端壓縮 支持初始化數(shù)據(jù) 相關(guān)功能及資源分析 基本功能先到https://www.npmjs.com/search?q=vue+upload上搜索有關(guān)上傳的控件,沒(méi)有完全滿(mǎn)足需求的組件,過(guò)濾后找到...

    wangbjun 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<