亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

如何對消耗g云存儲的代碼進行單元測試?

如何對消耗g云存儲的代碼進行單元測試?

Go
眼眸繁星 2022-09-19 17:35:40
我想為下面的代碼編寫單元測試package mainimport (    "context"    "google.golang.org/api/option"    "cloud.google.com/go/storage")var (    NewClient = storage.NewClient)func InitializeClient(ctx context.Context) (*storage.Client, error) {    credFilePath := "Storage credentials path."    // Creates a client.    client, err := NewClient(ctx, option.WithCredentialsFile(credFilePath))    if err != nil {        return nil, err    }    return client, nil}func createStorageBucket(ctx context.Context, client *storage.Client, bucketName string) (*storage.BucketHandle, error) {    // Sets your Google Cloud Platform project ID.    projectID := "Some project id"    // Creates a Bucket instance.    bucket := client.Bucket(bucketName)    // Creates the new bucket.    ctx, cancel := context.WithTimeout(ctx, time.Second*10)    defer cancel()    if err := bucket.Create(ctx, projectID, nil); err != nil {        return nil, err    }    return bucket, nil}func bucketExists(ctx context.Context, client *storage.Client, bucketName string) error {    bucket := client.Bucket(bucketName)    if _, err := bucket.Attrs(ctx); err != nil {        //try creating the bucket        if _, err := createStorageBucket(ctx, client, bucketName); err != nil {            return err        }    }    return nil}func main() {    ctx = context.Background()    client, err := InitializeClient(ctx)    bucketName := "Some bucket name"    err = bucketExists(ctx, client, bucketName)}桶。創建() 和存儲桶。Attrs() 是 http 調用,也是返回結構的存儲桶()、對象() 和 NewReader() (所以在我看來,對于這個用例,實現接口沒有任何意義)注意:存儲。NewClient() 也是 http 調用,但我通過提供自定義實現來避免在我的測試中使用猴子路徑應用進行外部調用。var (    NewClient = storage.NewClient)
查看完整描述

1 回答

?
catspeake

TA貢獻1111條經驗 獲得超0個贊

代碼非常薄,很難弄清楚如何對其進行測試。


我猜弗利姆齊在標題中理解了這一點。


由于/在標題中,存在一個根本性的誤解。How to write unit test for gcloud storage?


好吧,我們不應該。他們做到了。一個更好的標題是,我不是想在這里挑剔,而是解釋我試圖解決這個問題的理解。How to unit test code consuming gcloud storage?


所以無論如何,這整件事導致我寫更少的瘦代碼,這樣我就可以測試我寫的代碼,驅動存儲的行,是否做了我們期望它做的事情。


這整件事是如此復雜,沒有錫空氣,我認為它不會回答你的問題。


但無論如何,如果這有助于思考這個困難,那已經是一個勝利。


package main


import (

    "context"

    "flag"

    "fmt"

    "testing"

    "time"


    "cloud.google.com/go/storage"

    "google.golang.org/api/option"

)


type client struct {

    c         *storage.Client

    projectID string

}


func New() client {

    return client{}

}


func (c *client) Initialize(ctx context.Context, projectID string) error {

    credFilePath := "Storage credentials path."

    x, err := NewClient(ctx, option.WithCredentialsFile(credFilePath))

    if err == nil {

        c.c = x

        c.projectID = projectID

    }

    return err

}


func (c client) BucketExists(ctx context.Context, bucketName string) bool {

    if c.c == nil {

        return nil, fmt.Errorf("not initialized")

    }

    bucket := c.c.Bucket(bucketName)

    err := bucket.Attrs(ctx)

    return err == nil

}


func (c client) CreateBucket(ctx context.Context, bucketName string) (*storage.BucketHandle, error) {

    if c.c == nil {

        return nil, fmt.Errorf("not initialized")

    }

    bucket := c.c.Bucket(bucketName)

    err := bucket.Create(ctx, c.projectID, nil)

    if err != nil {

        return nil, err

    }

    return bucket, err

}


func (c client) CreateBucketIfNone(ctx context.Context, bucketName string) (*storage.BucketHandle, error) {

    if !c.BucketExists(bucketName) {

        return c.CreateBucket(ctx, c.projectID, bucketName)

    }

    return c.c.Bucket(bucketName), nil

}


type clientStorageProvider interface { // give it a better name..

    Initialize(ctx context.Context, projectID string) (err error)

    CreateBucketIfNone(ctx context.Context, bucketName string) (*storage.BucketHandle, error)

    CreateBucket(ctx context.Context, bucketName string) (*storage.BucketHandle, error)

    BucketExists(ctx context.Context, bucketName string) bool

}


func main() {

    flag.Parse()

    cmd := flag.Arg(0)

    projectID := flag.Arg(1)

    bucketName := flag.Arg(2)


    ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)

    defer cancel()


    client := New()


    if cmd == "create" {

        createBucket(ctx, client, projectID, bucketName)

    } else {

        // ... more

    }

}


// this is the part we are going to test.

func createBucket(ctx context.Context, client clientStorageProvider, projectID, bucketName string) error {

    err := client.Initialize(ctx, projectID)

    if err != nil {

        return err

    }

    return client.CreateBucketIfNone(bucketName)

  // maybe we want to apply retry strategy here,

  // and test that the retry was done;

}


type clientFaker struct {

    initErr         error

    createErr       error

    createIfNoneErr error

    bucketExistsErr error

}


func (c clientFaker) Initialize(ctx context.Context, projectID string) (err error) {

    return c.initErr

}

func (c clientFaker) CreateBucketIfNone(ctx context.Context, bucketName string) (*storage.BucketHandle, error) {

    return nil, c.createIfNoneErr

}

func (c clientFaker) CreateBucket(ctx context.Context, bucketName string) (*storage.BucketHandle, error) {

    return nil, c.createErr

}

func (c clientFaker) BucketExists(ctx context.Context, bucketName string) bool {

    return nil, c.bucketExistsErr

}


func TestCreateBucketWithFailedInit(t *testing.T) {

    c := clientFaker{

        initErr: fmt.Errorf("failed init"),

    }

    ctx := context.Background()

    err := createBucket(ctx, c, "", "")

    if err == nil {

        t.Fatalf("should have failed to initialize the bucket")

    }

}


// etc...

請注意,我不高興作為返回參數,太具體了,但我沒有使用它(我把它放在這里,因為它在那里,否則掛著),所以很難圍繞它設計一些東西。*storage.BucketHandle


注意2,可能會發生我的代碼無法完全編譯的情況。我有一個依賴性問題,我現在不想修復,它阻止我看到所有錯誤(它在這個過程中過早停止)


查看完整回答
反對 回復 2022-09-19
  • 1 回答
  • 0 關注
  • 97 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號