اختبار طبقة الويب باستخدام @WebMvcTest
اختبار طبقة الويب باستخدام @WebMvcTest
حين تكتب متحكّمًا REST تهتم بثلاثة أشياء: هل تستجيب نقطة النهاية للطريقة الصحيحة وعنوان URL الصحيح، وهل تعيّن جسم الطلب ومتغيرات المسار بشكل صحيح، وهل تُعيد رمز الحالة والـ JSON الصحيحَين؟ لا يعنيك على الإطلاق ما إذا كانت قاعدة البيانات متاحة. تحميل سياق التطبيق كاملًا — Hibernate وتجمّعات الاتصال وسماسرة الرسائل — للإجابة على هذه الأسئلة الثلاثة يُعدّ بطيئًا وهشًّا وغير ضروري. وهذه تحديدًا هي المشكلة التي يحلّها @WebMvcTest.
ما هو اختبار الشريحة؟
تحمّل اختبارات الشرائح في Spring Boot مجموعة فرعية محددة جيدًا من سياق التطبيق. @WebMvcTest هي شريحة طبقة الويب: تُشغّل بنية Spring MVC الأساسية (المرشحات، ومحلّلات الوسائط، ومحوّلات الرسائل، وDispatcherServlet) لكنها تستبعد عمدًا @Service و@Repository و@Component وإعداد JPA/قاعدة البيانات التلقائي. النتيجة سياقٌ يبدأ خلال مئات المللي ثانية بدلًا من ثوانٍ عدة، ولا يلمس قاعدة البيانات أبدًا.
@SpringBootTest يحمّل السياق بالكامل. @WebMvcTest يقع في المنتصف: تحصل على إرسال MVC حقيقي (إلغاء التسلسل، والتحقق من الصحة، ومعالجات الاستثناءات) دون تكلفة السياق الكامل.
إعداد @WebMvcTest
لنفترض أن لديك متحكمًا REST بسيطًا لإدارة المنتجات:
لاختبار هذا المتحكّم بمعزل عن غيره، ضع تعليق التوصيف @WebMvcTest على فئة الاختبار وحدّد المتحكّم قيد الاختبار:
ما يوفّره @WebMvcTest تلقائيًا
- كائن
MockMvcمُهيَّأ بالكامل — لا حاجة لاستدعاءMockMvcBuilders.standaloneSetup(). ObjectMapperالخاص بـ Jackson مُهيَّأ تمامًا كما في الإنتاج (المسلسِلات المخصصة، وتسجيل الوحدات، إلخ).- جميع فئات
@ControllerAdviceفي التطبيق مُحمَّلة — تُختبر معالجة الاستثناءات من البداية إلى النهاية. - المرشحات المسجّلة كـ beans في Spring مُطبَّقة (مرشحات الأمان، وCORS، إلخ).
- التحقق من صحة الـ Bean (
@Valid) مُربوط ويُطلق أثناء معالجة الطلب.
تحديد نطاق الشريحة: أي متحكمات تُحمَّل؟
حين تكتب @WebMvcTest(ProductController.class)، يُضاف ذلك المتحكم فقط إلى السياق. إن حذفت القيمة — @WebMvcTest بلا وسيطة — يحمّل Spring جميع كيانات @RestController و@Controller الموجودة في حزمك. وهذا يعني أن جميع تبعياتها يجب أن تُحاكى. فضّل الصيغة الصريحة لتُبقي الاختبارات ضيّقة وسريعة.
@WebMvcTest(MyController.class). مع نمو التطبيق، تسحب الصيغة بلا وسيطة متحكمات جديدة وتبعياتها من @MockBean بصمت، مما يُبطئ عملية البناء ويجعل تشخيص الأخطاء أصعب.
اختبار التحقق من صحة الـ Bean
لأن @Valid تُعالَج بواسطة طبقة MVC، فإن @WebMvcTest هو المكان المناسب للتحقق من رفض المدخلات غير الصالحة:
لا يستلزم هذا الاختبار خدمة أو قاعدة بيانات تعمل، ومع ذلك يُثبت أن قيد @NotBlank على CreateProductRequest.name مُوصَّل وسيُعيد 400 عند انتهاكه.
الأمان في @WebMvcTest
إن كان مشروعك يتضمن spring-boot-starter-security، يُطبّق @WebMvcTest إعداد الأمان الخاص بك تلقائيًا. ستُعيد نقاط النهاية التي تتطلب مصادقة 401 أو 403 في الاختبارات. لديك عدة خيارات:
- استخدم
@WithMockUser(منspring-security-test) لتشغيل طلب كمستخدم مصادَق عليه بعينه. - وفّر
@TestConfigurationمخصصًا يُخفّف الأمان لسياق الاختبار. - استدع
.with(SecurityMockMvcRequestPostProcessors.csrf())على طلبات POST/PUT حين يكون CSRF مفعّلًا.
excludeAutoConfiguration، ستتوقف عن اختبار عقد الأمان لواجهة API الخاصة بك. استخدم @WithMockUser أو إعداد أمان مخصصًا للاختبار يحتفظ بقواعد واقعية مع السماح بتنفيذ الاختبارات.
المقايضات في الأداء
شريحة الويب سريعة تحديدًا لأنها ضيّقة. لكن لهذا الضيق عواقبه: طبقتا الخدمة والمستودع غائبتان كليًّا، لذا يجب عليك محاكاة كل تبعية يستخدمها متحكمك بـ @MockBean. إن كان للمتحكم تبعيات متعاونة كثيرة قد يصبح ذلك مطوّلًا. الحد يُشير إلى قلق في التصميم: المتحكمات ذات التبعيات المباشرة الكثيرة أصعب اختبارًا وأصعب استيعابًا.
مقايضة أخرى هي تخزين السياق مؤقتًا. يخزّن Spring Boot السياق عبر الاختبارات التي تشترك في نفس الإعداد. إضافة تعريفات @MockBean مختلفة في فئات اختبار مختلفة يُنشئ إعدادات سياق مختلفة، مما يُعطّل التخزين المؤقت ويُبطئ مجموعة الاختبارات. اجمع المتحكمات ذات متطلبات المحاكاة نفسها في فئة اختبار واحدة كلما أمكن.
الخلاصة
يمنحك @WebMvcTest اختبار شريحة سريعًا ومركّزًا لطبقة الويب: إرسال MVC حقيقي، وتسلسل Jackson حقيقي، وتحقق Bean حقيقي، ومعالجات استثناءات حقيقية — مع صفر تكلفة لقاعدة البيانات. أعلن المتحكم المحدد قيد الاختبار، واستبدل جميع الخدمات بـ @MockBean، واستخدم MockMvc لإجراء تأكيدات على مستوى HTTP. يتناول الدرس التالي MockMvc بعمق أكبر ومجموعة التأكيدات والتخصيصات الغنية التي يوفّرها.