مقدمة
تقدم هذه المقالة كيفية استخدام Springboot+Junit+Mockito لاختبار الوحدة ، وحدد فئة تطابق المعاملات لإجراء اختبار الوحدة.
فهم المتطلبات قبل اختبار الوحدة
لكتابة اختبار واحد جيد ، يجب أولاً فهم المتطلبات. فقط من خلال معرفة ما يجب فعله ، يمكنك معرفة كيفية الاختبار. لكن هذا المقال يتحدث بشكل أساسي عن استخدام Mockito ، وليس هناك حاجة للانتباه إلى احتياجات محددة. لذلك ، يغفل هذا القسم وصف المتطلبات المحددة.
عزل التبعيات الخارجية
Case1. كيفية التحكم في قيمة إرجاع كائن التبعية المشروح بواسطة @autowired أو reresource التعليق التوضيحي في الفئة التي تم اختبارها
أخذ المطابقة (matchingorder buyorder ، matchingorder sellorder) للطريقة تحت اختبار MatchingServiceImpl.java كمثال
اختبار فئة MatchingServiceImpl
الطبقة العامة MatchingServiceImpl تنفذ Matchingservice {private static final logger log = loggerfactory.getLogger (MatchingServiceImpl.Class) ؛ absieservice Quoteservice abseeservice ... المطابقة العامة مطابقة (matchingorder buyorder ، matchingorder sellorder) {int currentPrice = quoteservice.getCurrentPriceBroduct (buyorder.getProductCode ()) ؛ نتيجة MatchingResult = جديد MatchingResult () ؛ if (sellorder! = null && buyorder! = null && sellorder.getPrice () <= buyorder.getPrice ()) {...}}Quoteservice.getCurrentPriceBroduct (buyorder.getProductCode ()) ؛ من أجل الوصول إلى redis للحصول على الاقتباس الحالي ، نحتاج إلى سخر من علامات Quoteservice التبعية الخارجية للتحكم في قيمة الإرجاع لطريقة GetCurrentPriceBroduct. يمكنك القيام بذلك باستخدام Mockito ، على النحو التالي:
اختبار فئة MatchingServiceImpltest
فئة Public MatchingServiceImpltest يمتد MockitObasedTest { / *** سيتم حقن الكائنات التي تحمل علامة @mock تلقائيًا في الكائن الذي يتميز به @enjectmocks* / mock private Quoteservice Quoteservice ؛ /** * <pre> * الكائنات التي سيتم اختبارها ، والتي تم وضع علامة عليها مع injectMocks ، سيتم حقن تلك الكائنات التي يحمل علامة @mock تلقائيًا. * نقطة أخرى هي أن MatchingServiceImpl جديد مباشرة (لا بأس إذا لم يكن جديدًا بعد Mockito 1.9) ، بدلاً من الحقن من خلال حاوية الربيع. لأنه هنا لست بحاجة إلى الحصول على تبعيات أخرى من حاوية الربيع *، ولا أحتاج إلى قاعدة بيانات ، إعادة التدوير ، Zookeeper ، MQ ، ولا شيء يعتمد عليها ، لذلك أنا جديد *</ pre> */ @injectmocks Private MatchingServiceImplplisterviceervice (new MatchingServiceImpl () ؛ Test public void testMatching_SuccessWhenCencErentPriceBteneBuyPricEndSellPrice () {matchingorder buyorder = new MatchingOrder () ؛ buyorder.setPrice (1000) ؛ buyorder.setCount (23) ؛ matchingorder sellorder = new MatchingOrder () ؛ sellorder.setPrice (800) ؛ sellorder.setCount (20) ؛ // method stidbing (method stilbing) // عندما (x) .thenreturn (y): إرجاع القيمة المحددة عندما تسمى الطريقة المحددة mockito.hen (quoteservice.getCurrentPriceBroduct (mockito.anystring ())). MatchingResult Result = MatchingService.matching (buyorder ، sellorder) ؛ org.junit.assert.assertequals (true ، result.issuccess ()) ؛ // التأكيد على ما إذا كان التوفيق ناجحًا org.junit.assert.assertequals (20 ، result.getTradeCount ()) // تأكيد ما إذا كان آخر اقتباس يفي بالتوقعات}Case2. عندما يتم اختبار الوظيفة A ، كيفية التحكم في قيمة إرجاع الوظيفة B في الفئة قيد الاختبار؟
على سبيل المثال ، هناك وظيفة startBuyProcess في MatchingServiceImpl ، والتي تستدعي وظائف أخرى في الفصل ، مثل getTopsellOrder والمطابقة. كيفية التحكم في قيم الإرجاع لهاتين وظيفتين؟
المشكلة التي يجب حلها هنا هي في الواقع كيفية تنفيذ الطريقة المقاسة (مثل StartBuyProcess) لفئة "وهمية جزئية" التي تم اختبارها ، بينما يتم تكديس طرق أخرى (مثل getTopsellOrder) (لا تدخل وتنفيذها بالفعل).
اختبار فئة MatchingServiceImpl
Proted void StartBuyProcess (matchingorder buyorder ، waitformatching boolean) {بينما (صحيح) {// أفضل سعر لتوفيق الطرف المقابل TopSellOrder = getTopsellOrder (buyorder.getProductCode ()) ؛ MatchingResult MatchingResult = مطابقة (buyorder ، topSellOrder) ؛ if (matchingResult.issuccess ()) {DrocashingSuccess (buyorder ، topSellOrder ، MatchingResult ، MatchingType.Buy) ؛ if (buyorder.getCount () <= 0) {break ؛ }} else {if (waitformatching) {// إضافة لتطابق قائمة الانتظار لتكون مطابقة addToMatchingBuy (buyorder) ؛ } else {// recled the order sendcanclemsg (buyorder) ؛ } استراحة؛ }}}}باستخدام mockito.spy () يمكن أن يحقق "وهمية جزئية"
اختبار فئة MatchingServiceImpltest.TestStartBuyProcess_incaseofmatchingsuccess
/** * * اختبار ما إذا كانت معالجة طريقة startBuyProcess بعد التوفيق الناجح تلبي التوقعات ، أي اختبار السلوك بعد إدخال فرع الحكم التالي * {link matchingserviceimpl#startbuyprice ( * matchingorder ، boolean)} * <pre> * if (matchingresult.issuccess () MatchingType.Buy) ؛ * * if (buyorder.getCount () <= 0) { * break ؛ *} *} * </pre> * */ test public void testStartBuyProcess_incaseOfMatchingSucscess () {matchingorder buyorder = new MatchingOrder () ؛ buyorder.setPrice (700) ؛ buyorder.setCount (23) ؛ // استخدام mockito.spy () لوسادة جزئيا MatchingService MatchingService = mockito.spy (MatchingService) ؛ MatchingResult firstMatchingResult = جديد MatchingResult () ؛ FirstMatchingResult.SetSuccess (صواب) ؛ FirstMatchingResult.setTradeCount (20) ؛ MatchingResult SecondMatchingResult = جديد MatchingResult () ؛ SecondMatchingResult.SetSuccess (false) ؛ // doreturn (x). عندما (OBJ) .Method () بعد تراكم الأساليب ، بعد تراكم الأساليب ، سيعيد البرنامج القيمة المحددة كما هو متوقع عند تنفيذ هذه الأساليب. سيتم تنفيذ الأساليب التي لا يتم تكديسها في الوقت الفعلي. . .Matching (Mockito.any (MatchingOrder.Class) ، Mockito.any (MatchingOrder.Class)) ؛ matchingorder sellorder = new MatchingOrder () ؛ sellorder.setPrice (600) ؛ sellorder.setCount (20) ؛ // iding the getTopsellOrder method mockito.doreturn (sellorder). when (MatchingService) .getTopsellOrder (mockito.anystring ()) ؛ // تتراكم الطريقة الخارجية التي تعتمد على jedis mockito. // StartBuyProcess هي الوظيفة قيد الاختبار. إذا لم تتراكم ، MatchingService.StartBuyProcess (buyorder ، true) ؛ // إن التأكيد الفقير اللاحق هو اختبار سلوك طريقة الدوارات ، وهو أيضًا الغرض من هذا الاختبار. فيما يلي التحقق مما إذا كان jedisclient.zremfirst قد تم تنفيذه بمجرد mockito.verify (jedisclient ، mockito.times (1)). zremfirst (mockito.anystring ()) ؛ org.junit.assert.assertequals (3 ، buyorder.getCount ()) ؛ org.junit.assert.assertequals (0 ، sellorder.getCount ()) ؛ } وقد تم توضيح استخدام Spy. دعنا نتحدث عن "التفاصيل" لاختبارات الوحدة من TestStartBuyProcess_IncaseOfMatchingsuccess.
الغرض من TestStartBuyProcess_incaseofmatchingsuccess هو اختبار الدوارات. لقد عملنا بجد لإنهاء الاستعدادات السابقة قبل أن نتمكن من اختبار الدوارات.
يجب أن تكون الممارسة الأفضل هي بدء طريقة اختبار جديدة لاختبار الدوارات بشكل منفصل ، ويتم تركيز التركيز أيضًا. بعد كتابة DrocashingSuccess ، يمكن لـ StartBuyProcess في الواقع أن تغطي فرع الحكم الخاص بها. لا يزال يتم تحقيق التغطية ، ويكون رمز الاختبار أسهل في الحفاظ عليها. يتأثر TestStartBuyProcess_incaseofmatchingsuccess بسهولة بالتغيرات بسبب الكثير من المسؤوليات التي تم أخذها في الاعتبار. قد يؤثر تغيير الأشياء الصغيرة على وظيفتها الطبيعية.
إدخال تبعيات Maven الإطار الاختبار
<Rependency> <roupend> Junit </rougiD> <StifactId> Junit </stifactId> <soph> 4.11 </version> <scope> test </scope> </sependency> <sependency> <roupiD> org.mockito </rougeid> <StifactId> mockito-all </artifactid> <scope> test </scope> </sependency> <redency> <roupiD> org.springframework </rougiD> <artifactid> اختبار النابض </insifactid> <الإصدار> 4.2.5
سياق بناء سبرينغ بوت+جونيت+mockito
mockitobasedtest
runwith (springjunit4classrunner.class) springapplicationConfiguration (classes = testapplication.class) الفئة المجردة العامة mockitobasedtest { @before public void setup () rems {// تهيئة جميع كائنات mock ملحقة من قبل مراسيم mockito في حالة اختبار mockitoants.init (this) ؛ }} // فئات الاختبار الأخرى ترث mockitobasedtest ما سبق هو كل محتوى هذه المقالة. آمل أن يكون ذلك مفيدًا لتعلم الجميع وآمل أن يدعم الجميع wulin.com أكثر.