يتزوج ، بذرة والجواسيس في إطار سبوك

يوفر Spock 3 أدوات قوية (ولكن مختلفة في جوهرها) تعمل على تبسيط اختبارات الكتابة: Mock و Stub و Spy.



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


غالبًا ما يتم تصميم اختبارات الوحدة لاختبار فئة معزولة واحدة باستخدام أشكال مختلفة من mok: Mock و Stub و Spy. لذلك ستكون الاختبارات أكثر موثوقية وأقل عرضة للانهيار مع تطور رمز التبعية.


مثل هذه الاختبارات المعزولة أقل عرضة للمشاكل عند تغيير التفاصيل الداخلية لتطبيق التبعية.


من أحد المترجمين: في كل مرة أستخدم فيها Spock Framework لكتابة الاختبارات ، أشعر أنني أستطيع ارتكاب خطأ عند اختيار طريقة لاستبدال التبعيات. تحتوي هذه المقالة على أقصر ورقة خداع ممكنة لاختيار آلية لإنشاء mokas.


TL ؛ د


يسخر


استخدام وهمية ل:


  • الشيكات العقد بين رمز الاختبار والتبعيات
  • التحقق من أن أساليب التبعية تسمى العدد الصحيح من المرات
  • التحقق من صحة المعلمات التي يتم استدعاء رمز التبعية

بذرة


استخدم كعب الروتين إلى:


  • تقديم نتائج مكالمة محددة مسبقا
  • تنفيذ الإجراءات المحددة مسبقًا المتوقعة من التبعيات ، مثل رمي الاستثناءات

جواسيس


جواسيس الخوف. كما تقول وثائق سبوك:


فكر مرتين قبل استخدام هذه الآلية. ربما يجب عليك إعادة تصميم الحل الخاص بك وإعادة تنظيم التعليمات البرمجية الخاصة بك.

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


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


استخدام الجاسوس ل:


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

يسخر



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


FooController.groovy


 package com.mycompany.myapp import groovy.transform.CompileStatic @CompileStatic class FooController { FooService fooService def doSomething() { render fooService.doSomething("Sally") } } 

FooService.groovy


 package com.mycompany.myapp import groovy.transform.CompileStatic @CompileStatic class FooService { String doSomething(String name) { "Hi ${name}, FooService did something" } } 

في هذا السيناريو ، نريد أن نكتب اختبارًا سيختبر:


  • العقد بين FooController و FooService
  • FooService.doSomething(name) بالعدد الصحيح من المرات
  • FooService.doSomething(name) مع المعلمة الصحيحة

ألقِ نظرة على الاختبار:


MockSpec.groovy


 package com.mycompany.myapp import grails.testing.web.controllers.ControllerUnitTest import spock.lang.Specification class MockSpec extends Specification implements ControllerUnitTest<FooController> { void "Mock FooService"() { given: "  " def fooService = Mock(FooService) and: "    " controller.fooService = fooService when: "  " controller.doSomething() then: "         " 1 * fooService.doSomething("Sally") and: "  ''    - 'null'" response.text == null.toString() } } 

الاختبار أعلاه يخلق خدمة وهمية:


 def fooService = Mock(FooService) 

يتحقق الاختبار أيضًا من FooService.doSomething(name) مرة واحدة ، والمعلمة التي تم تمريرها إليه تطابق السلسلة "Sally" .


 1 * fooService.doSomething("Sally") 

الكود أعلاه يحل 4 مشاكل مهمة:


  • يخلق وهمية ل FooService
  • يتحقق من FooService.doSomething(String name) مرة واحدة تمامًا باستخدام المعلمة String والقيمة "Sally"
  • عزل رمز الاختبار ، لتحل محل تنفيذ التبعية

بذرة


هل تستخدم الشفرة المختبرة التبعيات؟ هل الغرض من الاختبار هو التأكد من أن الشفرة قيد الاختبار تعمل بشكل صحيح عند التفاعل مع التبعيات؟ هل نتائج مكالمات أساليب التبعية هي قيم إدخال الكود قيد الاختبار؟


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


دعونا نلقي نظرة على المثال التالي مع FooController و FooService واختبار وظيفة وحدة التحكم باستخدام FooService الروتين.


FooController.groovy


 package com.mycompany.myapp import groovy.transform.CompileStatic @CompileStatic class FooController { FooService fooService def doSomething() { render fooService.doSomething("Sally") } } 

FooService.groovy


 package com.mycompany.myapp import groovy.transform.CompileStatic @CompileStatic class FooService { String doSomething(String name) { "Hi ${name}, FooService did something" } } 

كود الاختبار:


StubSpec.groovy


 package com.mycompany.myapp import grails.testing.web.controllers.ControllerUnitTest import spock.lang.Specification class StubSpec extends Specification implements ControllerUnitTest<FooController> { void "Stub FooService"() { given: "  " def fooService = Stub(FooService) { doSomething(_) >> "Stub did something" } and: "    " controller.fooService = fooService when: "  " controller.doSomething() then: "   " // 1 * fooService.doSomething() //        response.text == "Stub did something" } } 

يمكنك إنشاء كعب روتين مثل هذا:


 def fooService = Stub(FooService) { doSomething(_) >> "Stub did something" } 

الكود أعلاه يحل 4 مشاكل مهمة:


  • يخلق كعب FooService
  • يتأكد من أن FooService.doSomething(String name) سيعود السلسلة "Stub did something" بغض النظر عن المعلمة التي تم تمريرها (لذلك استخدمنا الحرف _ )
  • عزل الكود الذي تم اختباره ، واستبدال تطبيق التبعية بنقرة

جواسيس


من فضلك لا تقرأ هذا القسم.


لا تنظر.


انتقل إلى المرحلة التالية.


هل ما زلت تقرأ؟ حسنًا ، حسنًا ، دعنا نتعامل مع Spy.



لا تستخدم الجاسوس. كما تقول وثائق سبوك:


فكر مرتين قبل استخدام هذه الآلية. ربما يجب عليك إعادة تصميم الحل الخاص بك وإعادة تنظيم التعليمات البرمجية الخاصة بك.

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


الجواسيس مختلفون عن mokas أو بذرة العنب لأنها لا تعمل مثل العقب.


عندما يتم استبدال التبعية بـ mok أو كعب الروتين ، يتم إنشاء كائن اختبار ، ولا يتم تنفيذ التعليمات البرمجية المصدر الحقيقي للتبعية.


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


لنلقِ نظرة على مثال FooController التالي ، والذي يستخدم FooService ، ثم اختبر الوظيفة باستخدام جاسوس.


FooController.groovy


 package com.mycompany.myapp import groovy.transform.CompileStatic @CompileStatic class FooController { FooService fooService def doSomething() { render fooService.doSomething("Sally") } } 

FooService.groovy


 package com.mycompany.myapp import groovy.transform.CompileStatic @CompileStatic class FooService { String doSomething(String name) { "Hi ${name}, FooService did something" } } 

كود الاختبار:


SpySpec.groovy


 package com.mycompany.myapp import grails.testing.web.controllers.ControllerUnitTest import spock.lang.Specification class SpySpec extends Specification implements ControllerUnitTest<FooController> { void "Spy FooService"() { given: " -" def fooService = Spy(FooService) and: "   " controller.fooService = fooService when: "  " controller.doSomething() then: "     " 1 * fooService.doSomething("Sally") >> "A Spy can modify implementation" and: '     ' response.text == "A Spy can modify implementation" } } 

إنشاء مثيل تجسس بسيط جدًا:


 def fooService = Spy(FooService) 

في الكود أعلاه ، يسمح لنا الجاسوس بالتحقق من الاتصال بـ FooService.doSomething(name) ، وعدد المكالمات وقيم المعلمة. علاوة على ذلك ، يغير الجاسوس تطبيق الطريقة لإرجاع قيمة مختلفة.


 1 * fooService.doSomething("Sally") >> "A Spy can modify implementation" 

الكود أعلاه يحل 4 مشاكل مهمة:


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

التعليمات


أي خيار لاستخدام: وهمية ، كعب رقيق أو جاسوس؟


هذا هو السؤال الذي يواجهه العديد من المطورين. يمكن أن تساعد الأسئلة الشائعة إذا لم تكن متأكدًا من الطريقة التي يجب استخدامها.


س: هل الغرض من اختبار التحقق من العقد بين الكود الذي تم اختباره والتبعيات؟


ج: إذا أجبت بنعم ، استخدم Mock


س: هل الغرض من الاختبار هو التأكد من أن الشفرة قيد الاختبار تعمل بشكل صحيح عند التفاعل مع التبعيات؟


ج: إذا أجبت بنعم ، استخدم Stub


س: هل نتائج استدعاء أساليب التبعية قيم إدخال الكود قيد الاختبار؟


ج: إذا أجبت بنعم ، استخدم Stub


س: هل تتعامل مع الشفرة القديمة ، والتي يصعب اختبارها للغاية ، وليس لديك أي خيارات متبقية؟


ج: حاول استخدام الجاسوس


مثال رمز


يمكنك العثور على الكود لجميع الأمثلة في هذه المقالة على:


https://github.com/ddelponte/mock-stub-spy


روابط مفيدة


Source: https://habr.com/ru/post/ar435488/


All Articles