আতঙ্ক কীভাবে পরীক্ষা করবেন?


90

আমি বর্তমানে চিন্তাভাবনা করছি যে পরীক্ষাগুলি কীভাবে লিখতে হবে যা যদি কোনও প্রদত্ত কোডের টুকরা আতঙ্কিত হয় কিনা তা পরীক্ষা করে? আমি জানি যে গো recoverপ্যানিক্সগুলি ধরতে ব্যবহার করে, তবে জাভা কোডের বিপরীতে, আপনি কোনও প্যানিকের ক্ষেত্রে কী কোডটি এড়াতে হবে বা আপনার কী আছে তা সত্যই আপনি নির্দিষ্ট করতে পারবেন না। সুতরাং আমার যদি একটি ফাংশন থাকে:

func f(t *testing.T) {
    defer func() {
        if r := recover(); r != nil {
            fmt.Println("Recovered in f", r)
        }
    }()
    OtherFunctionThatPanics()
    t.Errorf("The code did not panic")
}

OtherFunctionThatPanicsআতঙ্কিত হয়েছিল এবং আমরা পুনরুদ্ধার করেছি, বা ফাংশনটি মোটেই আতঙ্কিত হয় নি তা আমি সত্যিই বলতে পারি না । আতঙ্ক না থাকলে কোন কোডটি ছাড়তে হবে এবং আতঙ্ক থাকলে কোন কোডটি কার্যকর করতে হবে তা আমি কীভাবে নির্দিষ্ট করব? আমরা কীভাবে পরীক্ষা করতে পারি যে আমরা উদ্ধার করেছি এমন কিছু আতঙ্ক রয়েছে কিনা?

উত্তর:


106

testingসত্যই "সাফল্য," কেবলমাত্র ব্যর্থতার ধারণা নেই। সুতরাং আপনার উপরের কোডটি প্রায় সঠিক। আপনি এই স্টাইলটি কিছুটা আরও স্পষ্ট দেখতে পাবেন তবে এটি মূলত একই জিনিস।

func TestPanic(t *testing.T) {
    defer func() {
        if r := recover(); r == nil {
            t.Errorf("The code did not panic")
        }
    }()

    // The following is the code under test
    OtherFunctionThatPanics()
}

আমি সাধারণত testingমোটামুটি দুর্বল বলে মনে করি। আপনি জিংকোর মতো আরও শক্তিশালী পরীক্ষার ইঞ্জিনগুলিতে আগ্রহী হতে পারেন । আপনি যদি পুরো জিঙ্কগো সিস্টেম না চান তবে আপনি কেবল এর ম্যাচারের লাইব্রেরি গোমেগা ব্যবহার করতে পারেন যা পাশাপাশি ব্যবহার করা যেতে পারে testing। গোমেগায় ম্যাচারগুলির মতো রয়েছে:

Expect(OtherFunctionThatPanics).To(Panic())

আপনি প্যানিক-চেকিং কোনও সাধারণ কার্যক্রমেও গুটিয়ে রাখতে পারেন:

func TestPanic(t *testing.T) {
    assertPanic(t, OtherFunctionThatPanics)
}

func assertPanic(t *testing.T, f func()) {
    defer func() {
        if r := recover(); r == nil {
            t.Errorf("The code did not panic")
        }
    }()
    f()
}

রব নেপিয়ারের দ্বারা বর্ণিত প্রথম ফর্মটি ব্যবহার করে Go 1.11-এ ইগোরমিকুশকিন আসলে কভারেজের জন্য কাজ করে।
এফজিএম

আপনি কোন কারণ ব্যবহার করেন r := recover(); r == nilএবং না শুধুমাত্র recover() == nil?
ডানকান জোনস

@ ডানকানজোনস আসলে এই ক্ষেত্রে নয়। এটি ব্লকটিতে ত্রুটিটি উপলব্ধ করার জন্য এটি একটি সত্যিই গো প্যাটার্ন, সুতরাং ওপিকে সম্ভবত সেভাবে এটি লেখার অভ্যাস ছিল (এবং আমি তার কোডটি এগিয়ে নিয়ে এসেছি), তবে এটি বাস্তবে ব্যবহৃত হয় না।
রব নেপিয়ার

43

আপনি যদি সাক্ষ্য / দাবী ব্যবহার করেন তবে এটি একটি ওয়ান-লাইনার:

func TestOtherFunctionThatPanics(t *testing.T) {
  assert.Panics(t, OtherFunctionThatPanics, "The code did not panic")
}

বা, যদি আপনার OtherFunctionThatPanicsস্বাক্ষর ব্যতীত অন্য কোনও স্বাক্ষর থাকে func():

func TestOtherFunctionThatPanics(t *testing.T) {
  assert.Panics(t, func() { OtherFunctionThatPanics(arg) }, "The code did not panic")
}

আপনি যদি এখনও সাক্ষ্য দেওয়ার চেষ্টা না করে থাকেন, তবে সাক্ষ্য / উপহাসের পরীক্ষা করে দেখুন । দুর্দান্ত সরল জোর এবং বিদ্রূপ।


7

একাধিক পরীক্ষার কেসগুলি লুপ করার সময় আমি এই জাতীয় কিছু পেতে চাই:

package main

import (
    "reflect"
    "testing"
)


func TestYourFunc(t *testing.T) {
    type args struct {
        arg1 int
        arg2 int
        arg3 int
    }
    tests := []struct {
        name      string
        args      args
        want      []int
        wantErr   bool
        wantPanic bool
    }{
        //TODO: write test cases
    }
    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            defer func() {
                r := recover()
                if (r != nil) != tt.wantPanic {
                    t.Errorf("SequenceInt() recover = %v, wantPanic = %v", r, tt.wantPanic)
                }
            }()
            got, err := YourFunc(tt.args.arg1, tt.args.arg2, tt.args.arg3)
            if (err != nil) != tt.wantErr {
                t.Errorf("YourFunc() error = %v, wantErr %v", err, tt.wantErr)
                return
            }
            if !reflect.DeepEqual(got, tt.want) {
                t.Errorf("YourFunc() = %v, want %v", got, tt.want)
            }
        })
    }
}

খেলার মাঠে যান


4

আপনার যখন আতঙ্কের বিষয়বস্তুটি পরীক্ষা করতে হবে, আপনি পুনরুদ্ধার করা মানটি টাইপকাস্ট করতে পারেন:

func TestIsAheadComparedToPanicsWithDifferingStreams(t *testing.T) {
    defer func() {
        err := recover().(error)

        if err.Error() != "Cursor: cannot compare cursors from different streams" {
            t.Fatalf("Wrong panic message: %s", err.Error())
        }
    }()

    c1 := CursorFromserializedMust("/foo:0:0")
    c2 := CursorFromserializedMust("/bar:0:0")

    // must panic
    c1.IsAheadComparedTo(c2)
}

আপনি যে কোডটি পরীক্ষা করছেন তা যদি ত্রুটি বা ত্রুটি বার্তার সাথে আতঙ্ক না করে বা আতঙ্কিত না করে বা আপনি যে প্রত্যাশা করছেন ত্রুটি বার্তাটি দিয়ে থাকে তবে পরীক্ষাটি ব্যর্থ হবে (যা আপনি চান)।


4
ত্রুটি বার্তাগুলির তুলনা করার চেয়ে নির্দিষ্ট ত্রুটির ধরণের (যেমন, os.SyscallError) টাইপ করা আরও শক্তিশালী, যা (যেমন) এক গো থেকে রিলিজ পরবর্তী রিলিজ করতে পারে।
মাইকেল

+ মাইকেল অগস্ট, সম্ভবত এটির থেকে আরও ভাল উপায়, যখন কোনও নির্দিষ্ট ধরণের উপলব্ধ থাকে।
junas.fi

3

আপনার ক্ষেত্রে আপনি এটি করতে পারেন:

func f(t *testing.T) {
    recovered := func() (r bool) {
        defer func() {
            if r := recover(); r != nil {
                r = true
            }
        }()
        OtherFunctionThatPanics()
        // NOT BE EXECUTED IF PANICS
        // ....
    }
    if ! recovered() {
        t.Errorf("The code did not panic")

        // EXECUTED IF PANICS
        // ....
    }
}

জেনেরিক প্যানিক রাউটার ফাংশন হিসাবে এটি কাজ করবে:

https://github.com/7d4b9/recover

package recover

func Recovered(IfPanic, Else func(), Then func(recover interface{})) (recoverElse interface{}) {
    defer func() {
        if r := recover(); r != nil {
            {
                // EXECUTED IF PANICS
                if Then != nil {
                    Then(r)
                }
            }
        }
    }()

    IfPanic()

    {
        // NOT BE EXECUTED IF PANICS
        if Else != nil {
            defer func() {
                recoverElse = recover()
            }()
            Else()
        }
    }
    return
}

var testError = errors.New("expected error")

func TestRecover(t *testing.T) {
    Recovered(
        func() {
            panic(testError)
        },
        func() {
            t.Errorf("The code did not panic")
        },
        func(r interface{}) {
            if err := r.(error); err != nil {
                assert.Error(t, testError, err)
                return
            }
            t.Errorf("The code did an unexpected panic")
        },
    )
}

3

সুসিনেক্ট ওয়ে

আমার কাছে, নীচের সমাধানটি পড়া সহজ এবং আপনাকে পরীক্ষার অধীনে কোডটির প্রাকৃতিক কোড প্রবাহ দেখায়।

func TestPanic(t *testing.T) {
    // No need to check whether `recover()` is nil. Just turn off the panic.
    defer func() { recover() }()

    OtherFunctionThatPanics()

    // Never reaches here if `OtherFunctionThatPanics` panics.
    t.Errorf("did not panic")
}

আরও সাধারণ সমাধানের জন্য, আপনি এটি এর মতো করেও করতে পারেন:

func TestPanic(t *testing.T) {
    shouldPanic(t, OtherFunctionThatPanics)
}

func shouldPanic(t *testing.T, f func()) {
    defer func() { recover() }()
    f()
    t.Errorf("should have panicked")
}

0

আতঙ্ককে কোনও ইনপুট দিয়ে কোন ক্রিয়াকলাপটি পিনসেড তা পরীক্ষা করতে পারেন

package main

import "fmt"

func explode() {
    // Cause a panic.
    panic("WRONG")
}

func explode1() {
    // Cause a panic.
    panic("WRONG1")
}

func main() {
    // Handle errors in defer func with recover.
    defer func() {
        if r := recover(); r != nil {
            var ok bool
            err, ok := r.(error)
            if !ok {
                err = fmt.Errorf("pkg: %v", r)
                fmt.Println(err)
            }
        }

    }()
    // These causes an error. change between these
    explode()
    //explode1()

    fmt.Println("Everything fine")

}

http://play.golang.org/p/ORWBqmPSVA

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.