الذهاب أفضل الممارسات - اختبار

في الأيام الأولى من حياتي المهنية في البرمجة لم أكن أرى حقًا القيمة وأعتقد أنها تكررت العمل. ومع ذلك ، فإنني عادة ما أهدف إلى تغطية اختبار بنسبة 90-100 ٪ على كل ما أكتب. وأعتقد بشكل عام أن الاختبار على كل طبقة يعد ممارسة جيدة (سنعود إلى ذلك).

في الواقع ، عند النظر إلى قواعد الشفرات التي أمتلكها أمامي يوميًا ، فإن أكثر ما أخشى تغييره هو القواعد التي لدي أقل تغطية اختبار. وهذا في نهاية المطاف يقلل من إنتاجي والتسليمات لدينا. من الواضح بالنسبة لي أن التغطية العالية للاختبار تساوي جودة أعلى وإنتاجية أعلى.

اختبار على كل طبقة

سنغوص في مثال على الفور. افترض أن لديك تطبيقًا بهيكله التالي.

نموذج التطبيق

هناك بعض المكونات المشتركة ، مثل النماذج والمعالجات. ثم لديك طريقتان مختلفتان للتفاعل مع هذا التطبيق ، على سبيل المثال CLI أو HTTP API أو RPCs Thrift. لقد وجدت أنه من الممارسات الجيدة التأكد من أنك لا تختبر فقط الطرز أو معالجاتها فقط ، بل جميعها. حتى لنفس الميزة. لأنه صحيح ولكن بالضرورة أنك إذا قمت بتنفيذ دعم للميزة X في المعالج ، فهي متوفرة بالفعل عبر واجهات HTTP و Thrift على سبيل المثال.

هذا سيكون أكثر ثقة في إجراء تغييرات على منطقك ، حتى في عمق التطبيق.

الاختبارات القائمة على الجدول

في جميع الحالات تقريبًا ، عندما تختبر طريقة ترغب في اختبار سيناريوهين على الوظيفة. عادةً مع معلمات إدخال مختلفة أو استجابات وهمية مختلفة. أرغب في تجميع كل هذه الاختبارات في وظيفة Test * واحدة ومن ثم امتلك حلقة تعمل في جميع حالات الاختبار. إليك مثال أساسي:

func TestDivision (t * testing.T) {
    الاختبارات: = [] هيكل {
        س float64
        ذ float64
        نتيجة float64
        يخطئ خطأ
    } {
        {x: 1.0 ، y: 2.0 ، النتيجة: 0.5 ، err: nil} ،
        {x: -1.0 ، y: 2.0 ، النتيجة: -0.5 ، err: nil} ،
        {x: 1.0 ، y: 0.0 ، النتيجة: 0.0 ، err: ErrZeroDivision} ،
    }
    لـ _ ، اختبار: = اختبارات المدى
        النتيجة ، يخطئ: = divide (test.x ، test.y)
        assert.IsType (t ، test.err ، err)
        assert.Equal (t ، test.result ، النتيجة)
    }
}

لا تغطي الاختبارات المذكورة أعلاه كل شيء ، بل تُعد بمثابة مثال لكيفية اختبار النتائج والأخطاء المتوقعة. يستخدم الكود أعلاه أيضًا حزمة الشهادة الكبيرة للتأكيدات.

التعزيز ، الاختبارات القائمة على الجدول مع حالات الاختبار المسماة

إذا كان لديك العديد من الاختبارات أو في كثير من الأحيان مطورين جدد ليسوا على دراية بقاعدة الكود ، فقد يكون من المفيد تسمية اختباراتك. فيما يلي مثال قصير لما سيكون عليه الأمر

الاختبارات: = خريطة [سلسلة] هيكل {
    عدد الباحثين
    خطأ smsErr
    يخطئ خطأ
} {
    "نجاح": {0132423444 ، لا شيء ، لا شيء} ،
    "نشر الخطأ": {0132423444 ، sampleErr ، sampleErr} ،
}

لاحظ أن هناك فرقًا هنا بين وجود خريطة وشريحة. الخريطة لا تضمن النظام ، في حين أن الشريحة لا.

الاستهزاء باستخدام السخرية

تعد الواجهات نقاط تكامل جيدة جدًا بشكل طبيعي للاختبارات ، حيث يمكن بسهولة استبدال تطبيق الواجهة من خلال تطبيق وهمي. ومع ذلك ، يمكن أن تكون كتابة mocks مملة جدا ومملة. لتسهيل الحياة ، فأنا أستخدم السخرية لتكوين أحزاني استنادًا إلى واجهة معينة.

دعونا نلقي نظرة على كيفية التعامل مع ذلك. افترض أن لدينا الواجهة التالية.

اكتب واجهة SMS
    إرسال (عدد int ، سلسلة نصية) خطأ
}

إليك تطبيق وهمية باستخدام هذه الواجهة:

/ / Messager هو بنية معالجة الرسائل من أنواع مختلفة.
نوع هيكل المساجر
    الرسائل القصيرة SMS
}
// SendHelloWorld يرسل رسالة Hello world.
خطأ func (m * Messager) خطأ SendHelloWorld (رقم الباحث) {
    err: = m.sms.Send (الرقم ، "مرحبًا ، العالم!")
    إذا أخطأت! = لا شيء
        عودة يخطئ
    }
    عودة لا شيء
}

يمكننا الآن استخدام Mockery لإنشاء محاكاة لواجهة SMS. إليك الشكل الذي سيبدو عليه (يستخدم هذا المثال علامة -inpkg التي تضع الوهمية في نفس الحزمة مثل الواجهة).

// MockSMS هو نوع هجائي تم إنشاؤه تلقائيًا لنوع الرسائل القصيرة
اكتب هيكل MockSMS
    mock.Mock
}
// إرسال يوفر وظيفة وهمية مع الحقول المعينة: رقم ، النص
خطأ في إرسال (رقم العدد ، سلسلة نصية) func (_m * MockSMS) {
    ret: = _m.Called (رقم ، نص)
    فار r0 خطأ
    إذا كانت rf ، حسناً: = ret.Get (0). (خطأ func (int ، string)) ؛ حسنا {
        r0 = rf (رقم ، نص)
    } آخر {
        r0 = ret.Error (0)
    }
    عودة r0
}
var _ SMS = (* MockSMS) (لا شيء)

بنية الرسائل القصيرة هي وراثة من testify mock.Mock ، والذي يعطينا بعض الخيارات المثيرة للاهتمام عند كتابة حالات الاختبار. لذا ، فقد حان الوقت الآن لكتابة اختبارنا لطريقة SendHelloWorld باستخدام الوهمية من Mockery.

func TestSendHelloWorld (t * testing.T) {
    sampleErr: = errors.New ("some error")
    الاختبارات: = خريطة [سلسلة] هيكل {
        عدد الباحثين
        خطأ smsErr
        يخطئ خطأ
    } {
        "نجاح": {0132423444 ، لا شيء ، لا شيء} ،
        "نشر الخطأ": {0132423444 ، sampleErr ، sampleErr} ،
    }
    لـ _ ، اختبار: = اختبارات المدى
        sms: = & MockSMS {}
        sms.On ("Send" ، test.number ، "Hello، world!"). Return (test.smsErr) .Once ()
        m: = & Messager {
            الرسائل القصيرة: الرسائل القصيرة ،
        }
   
        err: = m.SendHelloWorld (test.number)
        assert.Equal (t ، test.err ، err)
        sms.AssertExpectations (ر)
    }
}

هناك بضع نقاط تستحق الذكر في رمز المثال أعلاه. في الاختبار ، ستلاحظ أنني أقوم بإنشاء مثيل MockSMS ثم استخدم .On () يمكنني تحديد ما يجب أن يحدث (.Return ()) عند إرسال معلمات معينة إلى النموذج.

أخيرًا ، أستخدم sms.AssertExpectations للتأكد من أنه تم استدعاء واجهة SMS بالعدد المتوقع من المرات. في هذه الحالة مرة واحدة ().

يمكن العثور على جميع الملفات أعلاه في هذا gist.

اختبارات الملفات الذهبية

في بعض الحالات ، وجدت أنه من المفيد أن أؤكد فقط أن نقطة استجابة كبيرة تظل كما هي. على سبيل المثال ، يمكن إرجاع البيانات من بيانات JSON من API. في هذه الحالة ، تعلمت من ميشيل هاشيموتو أن استخدام الملفات الذهبية إلى جانب أداة ذكية هو كشف علامات سطر الأوامر للاختبار.

الفكرة الأساسية هي أنك تكتب نص الاستجابة الصحيح إلى ملف (الملف الذهبي). ثم عند إجراء الاختبارات ، تقوم بإجراء مقارنة بايت بين الملف الذهبي واستجابة الاختبار.

لتسهيل إنشاء حزمة goldie ، التي تعالج إعداد إشارة سطر الأوامر وكتابة الملف الذهبي والمقارنة بشفافية.

فيما يلي مثال على كيفية استخدام goldie لهذا النوع من الاختبارات:

func TestExample (t * testing.T) {
    مسجل: = httptest.NewRecorder ()

    مسا ، يخطئ: = http.NewRequest ("GET" ، "/ example" ، لا شيء)
    assert.Nil (t ، err)

    معالج: = http.HandlerFunc (ExampleHandler)
    handler.ServeHTTP ()

    goldie.Assert (t ، "example"، recorder.Body.Bytes ())
}

عندما تحتاج إلى تحديث ملفك الذهبي ، فأنت تقوم بتشغيل ما يلي:

الذهاب اختبار تحديث ... / ...

وعندما تريد فقط إجراء الاختبارات ، يمكنك القيام بذلك كالمعتاد:

الذهاب اختبار. / ...

مع السلامة!

شكرا لالتصاق حتى النهاية! آمل أن تكون قد وجدت شيئًا مفيدًا في المقال.