كيفية اختبار الخدمات ونقاط النهاية والمستودعات في Spring Boot

سأوضح لك في هذا المنشور كيفية كتابة اختبارات الوحدة في تطبيقات التمهيد الربيعي.

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

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

لماذا تختبر الوحدة نقاط النهاية؟

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

لماذا خدمات اختبار الوحدة؟

يجب أن يكون واضحًا بالفعل ، ولكن فقط في حالة: نحتاج إلى التأكد من أن منطق العمل لدينا يعمل بشكل صحيح.

لماذا وحدة اختبار المستودعات؟

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

فكيف نختبر وحدات التحكم؟

حان الوقت الآن لتوضيح كيفية اختبار وحدات التحكم الخاصة بنا في التمهيد الربيعي. دعنا نتخيل أننا نكتب تطبيقًا يتيح لنا حفظ المستخدمين في قاعدة بيانات. نحدد كيان مستخدم وخدمة مستخدم ووحدة تحكم.

ملاحظة: الأمثلة الموضحة في هذا المنشور ليست لبنية استخدام الإنتاج الحقيقي

@[email protected] class User { @Id @GeneratedValue(generator = "uuid2") @GenericGenerator(name = "uuid2", strategy = "org.hibernate.id.UUIDGenerator") @Column(name = "id", columnDefinition = "BINARY(16)") private UUID id; private String name; private String email; private int age;}
@Datapublic class CreateUserRequest { private String name; private String email; private int age;}
@[email protected]("/users")public class UserController { UserService userService; @Autowired public UserController(UserService userService) { this.userService = userService; } @PostMapping public ResponseEntity createUser(@RequestBody CreateUserRequest request) { User created = userService.save(request); return ResponseEntity.ok(created); }}

تعتمد وحدة التحكم الخاصة بنا على UserService لكننا لسنا مهتمين بما تقدمه الخدمة الآن.

لنكتب الآن اختبار وحدة لوحدة التحكم الخاصة بنا للتأكد من أنها تعمل بشكل صحيح.

لقد سخرنا من خدمتنا لأننا لسنا بحاجة إلى تفاصيل تنفيذها. نحن فقط نختبر وحدة التحكم الخاصة بنا هنا. نستخدم MockMvcهنا لاختبار جهاز التحكم ومخطط الكائن لأغراض التسلسل.

نقوم بإعداد طريقتنا userService.Save() لإرجاع كائن المستخدم المطلوب. مررنا طلب إلى وحدة تحكم لدينا وبعد أن فحصنا البيانات التي تم إرجاعها مع السطر التالي: andExpect(jsonPath("$.name").value(request.getName())).

لدينا أيضًا طرق أخرى لاستخدامها. فيما يلي قائمة الطرق:

عندما نجري الاختبار نرى أنه نجح.

كيف نختبر الخدمات؟

الآن نذهب لاختبار UserService. إنه سهل الاختبار.

نحن نسخر من المستودع ونحقن نماذجنا في UserService. الآن عندما نجري الاختبار ، سنرى أنه نجح.

الآن دعنا نضيف قاعدة عمل إلى UserService: لنفترض أن المستخدم يجب أن يكون لديه عنوان بريد إلكتروني.

نقوم بتغيير طريقة الحفظ الخاصة بنا في UserService على النحو التالي:

public User save(CreateUserRequest request) { requireNonNull(request.getEmail()); User user = new User(); user.setName(request.getName()); user.setEmail(request.getEmail()); user.setAge(request.getAge()); userRepository.save(user); return user;}

عندما نجري الاختبار مرة أخرى ، سنرى اختبارًا فاشلاً.

قبل أن نصلحها ، دعنا نكتب اختبارًا يرضي هذا العمل.

لقد كتبنا اختبارًا جديدًا حدد أنه إذا أرسلنا بريدًا إلكترونيًا فارغًا ، فسيتم طرحه NullPointerException.

دعنا نصلح الاختبار الفاشل عن طريق إضافة بريد إلكتروني إلى طلبنا:

createUserRequest.setEmail("testemail");

قم بتشغيل كلا الاختبارين:

كيف نختبر المستودعات؟

الآن وصلنا إلى اختبار المستودعات. نستخدم قاعدة بيانات في الذاكرة h2 معTestEntityManager.

مستودعنا محدد على النحو التالي:

@Repositorypublic interface UserRepository extends JpaRepository, JpaSpecificationExecutor { Optional findById(UUID id);}

قم أولاً بتكوين h2db. قم بإنشاء تطبيق اسم الملف. yaml في الاختبار -> مسار الموارد:

spring: application: name: Spring Boot Rest API datasource: type: com.zaxxer.hikari.HikariDataSource url: "jdbc:h2:mem:test-api;INIT=CREATE SCHEMA IF NOT EXISTS dbo\\;CREATE SCHEMA IF NOT EXISTS definitions;DATABASE_TO_UPPER=false;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=false;MODE=MSSQLServer" name: password: username: initialization-mode: never hikari: schema: dbo jpa: database: H2 database-platform: org.hibernate.dialect.H2Dialect show-sql: true hibernate: ddl-auto: create-drop test: database: replace: none

ودعنا نكتب أولاً اختبارًا أساسيًا لمستودعنا: احفظ مستخدمًا واسترجعه:

@RunWith(SpringRunner.class)@DataJpaTestpublic class UserRepositoryTest { @Autowired TestEntityManager entityManager; @Autowired UserRepository sut; @Test public void it_should_save_user() { User user = new User(); user.setName("test user"); user = entityManager.persistAndFlush(user); assertThat(sut.findById(user.getId()).get()).isEqualTo(user); }}

عندما نقوم بتشغيله ، سنرى مجموعة من مخرجات وحدة التحكم ، وأيضًا اجتياز الاختبار الخاص بنا:

الآن دعنا نضيف طريقة أخرى إلى مستودعنا للبحث عن مستخدم عبر البريد الإلكتروني:

Optional findByEmail(String email);

واكتب اختبارًا آخر:

@Testpublic void it_should_find_user_byEmail() { User user = new User(); user.setEmail("[email protected]"); user = entityManager.persistAndFlush(user); assertThat(sut.findByEmail(user.getEmail()).get()).isEqualTo(user);}

عندما نلقي نظرة على وحدة التحكم بعد إجراء الاختبار ، سنرى SQL الذي تم إنشاؤه بواسطة السبات:

SELECT user0_.id AS id1_1_,user0_.age AS age2_1_,user0_.email AS email3_1_,user0_.name AS name4_1_FROM user user0_WHERE user0_.email=?

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

الآن ليس لديك أي أعذار لعدم كتابة اختبارات الوحدة! آمل أن يكون من الواضح لك كيفية كتابة اختبارات الوحدة لأنواع مختلفة من الأغراض.