คำนำ
บทความนี้แนะนำวิธีการใช้ Springboot+Junit+Mockito สำหรับการทดสอบหน่วยและเลือกคลาสที่ตรงกับธุรกรรมเพื่อทำการทดสอบหน่วย
เข้าใจข้อกำหนดก่อนการทดสอบหน่วย
ในการเขียนแบบทดสอบเดี่ยวที่ดีคุณต้องเข้าใจข้อกำหนดก่อน โดยรู้ว่าต้องทำอย่างไรคุณจะรู้วิธีทดสอบ แต่บทความนี้ส่วนใหญ่พูดถึงการใช้ Mockito และไม่จำเป็นต้องให้ความสนใจกับความต้องการเฉพาะ ดังนั้นส่วนนี้จะละเว้นคำอธิบายข้อกำหนดเฉพาะ
แยกการพึ่งพาภายนอก
case1. วิธีการควบคุมค่าส่งคืนของวัตถุการพึ่งพาหมายเหตุประกอบโดย @autowired หรือ @Resource Annotation ในคลาสที่ทดสอบ
ใช้การจับคู่ (MatchingOrder BuyOrder, MatchingOrder SellOrder) ของวิธีการภายใต้การทดสอบการจับคู่ VATCHINGICEIMPL.JAVA เป็นตัวอย่าง
การทดสอบคลาสที่ผ่านการทดสอบ
คลาสสาธารณะ MatchingServiceImpl ใช้ MatchingService {logger สุดท้ายคงที่ logger log = loggerFactory.getLogger (MatchingServiceImpl.class); @Autowired Private Quoteservice Quoteservice; ... การจับคู่สาธารณะการจับคู่ (MatchingOrder BuyOrder, MatchingOrder SellOrder) {int currentPrice = quoteservice.getCurrentPriceByProduct (buyOrder.getProductCode ()); MatchingResult result = new MatchingResult (); if (sellOrder! = null && buyorder! = null && sellOrder.getPrice () <= buyorder.getPrice ()) {... }}quoteservice.getCurrentPriceByProduct (buyOrder.getProductCode ()); ในการเข้าถึง REDIS เพื่อรับใบเสนอราคาปัจจุบันเราจำเป็นต้องเยาะเย้ยคำพูดการพึ่งพาภายนอกเพื่อควบคุมค่าผลตอบแทนของวิธี getCurrentPriceByProduct คุณสามารถทำได้โดยใช้ mockito ดังนี้:
การทดสอบคลาสการจับคู่
การจับคู่คลาสสาธารณะ MockitoBasedTest { / *** วัตถุที่ทำเครื่องหมายโดย @mock จะถูกฉีดลงในวัตถุที่ทำเครื่องหมายโดยอัตโนมัติโดย @injectmocks* / @mock private quoteservice quoteservice; /** * <pre> * วัตถุที่จะทดสอบทำเครื่องหมายด้วย @InjectMocks วัตถุเหล่านั้นที่ทำเครื่องหมายโดย @mock จะถูกฉีดเข้าไปโดยอัตโนมัติ * อีกจุดหนึ่งของหมายเหตุคือ MatchingServiceImpl ใหม่โดยตรง (ไม่เป็นไรถ้าไม่ใช่ของใหม่หลังจาก Mockito 1.9) แทนที่จะฉีดผ่านคอนเทนเนอร์สปริง เพราะที่นี่ฉันไม่จำเป็นต้องได้รับการพึ่งพาอื่น ๆ จากคอนเทนเนอร์ฤดูใบไม้ผลิ *และฉันไม่ต้องการฐานข้อมูล, Redis, Zookeeper, MQ และไม่มีอะไรขึ้นอยู่กับมันดังนั้นฉันจึงใหม่โดยตรง *</ pre> */ @InjectMocks การจับคู่ส่วนตัว @Test โมฆะสาธารณะ testMatching_successWhenCurrentPriceBetweenBuyPriceAndSellPrice () {MatchingOrder BuyOrder = new MatchingOrder (); BuyOrder.SetPrice (1,000); BuyOrder.setCount (23); MatchingOrder SellOrder = new MatchingOrder (); SellOrder.SetPrice (800); SellOrder.setCount (20); // วิธีการ stubbing (method stubbing) // เมื่อ (x) .thenreturn (y): ส่งคืนค่าที่ระบุเมื่อวิธีการที่ระบุเรียกว่า mockito เมื่อ (quoteservice.getCurrentPriceByProduct (mockito.anystring ())) MatchingResult result = MatchingService.Matching (BuyOrder, SellOrder); org.junit.assert.assertequals (จริง, result.issuccess ()); // ยืนยันว่าการจับคู่นั้นประสบความสำเร็จ org.junit.assert.assertequals (20, result.getTradecount ()); // ยืนยันว่าใบเสนอราคาล่าสุดตรงกับความคาดหวัง}case2. เมื่อมีการทดสอบฟังก์ชั่น A แล้ววิธีการควบคุมค่าส่งคืนของฟังก์ชั่น B ในชั้นเรียนภายใต้การทดสอบ?
ตัวอย่างเช่นมีฟังก์ชั่น startBuyProcess ใน MatchingServiceImpl ซึ่งเรียกฟังก์ชั่นอื่น ๆ ในชั้นเรียนเช่น getTopsellorder และการจับคู่ จะควบคุมค่าการส่งคืนของฟังก์ชั่นทั้งสองนี้ได้อย่างไร?
ปัญหาที่ต้องแก้ไขที่นี่เป็นจริงวิธีการดำเนินการวิธีการที่วัดได้ (เช่น startBuyProcess) ของคลาสที่ผ่านการทดสอบคลาส "MOCK บางส่วน" ในชั้นเรียนในขณะที่วิธีอื่น ๆ (เช่น getTopSellOrder) ถูกซ้อนกัน (ไม่ได้ดำเนินการจริง ๆ )
การทดสอบคลาสที่ผ่านการทดสอบ
Void startBuyProcess (MatchingOrder BuyOrder, Boolean WaitFormatching) {ในขณะที่ (จริง) {// ราคาที่ดีที่สุดของคู่หูที่จับคู่กับ TopSellOrder = getTopSellOrder (BuyOrder.getProductCode ()); MatchingResult MatchingResult = การจับคู่ (BuyOrder, TopSellOrder); if (matchingResult.issuccess ()) {domatchingsuccess (buyorder, topsellorder, matchingResult, matchingType.buy); if (buyorder.getCount () <= 0) {break; }} else {if (waitFormatching) {// เพิ่มเพื่อจับคู่คิวที่จะจับคู่ addTomatchingBuy (ซื้อ order); } else {// เพิกถอนคำสั่ง sendcanclemsg (buyorder); } หยุดพัก; -การใช้ mockito.spy () สามารถบรรลุ "mock บางส่วน"
การทดสอบคลาสการจับคู่ ServiceImpltest.testStartBuyProcess_incaseofmatchingsuccess
/** * * ทดสอบว่าการประมวลผลของวิธี startbuyprocess หลังจากการจับคู่ที่ประสบความสำเร็จตรงตามความคาดหวังนั่นคือทดสอบพฤติกรรมหลังจากเข้าสู่สาขาการตัดสินต่อไปนี้ * {@link matchingserviceimpl#startbuyprocess MatchingResult, MatchingType.buy); * * ถ้า (buyorder.getCount () <= 0) { * break; *} *} * </pre> * */ @Test โมฆะสาธารณะ TestStartBuyProcess_incaseofMatchingSuccess () {MatchingOrder BuyOrder = new MatchingOrder (); BuyOrder.SetPrice (700); BuyOrder.setCount (23); // ใช้ mockito.spy () เพื่อหมอนบางส่วนหมอน matchingservice matchingservice = mockito.spy (Matchingservice); MatchingResult FirstMatchingResult = new MatchingResult (); FirstMatchingResult.setsuccess (จริง); FirstMatchingResult.SetTradecount (20); MatchingResult SecondMatchingResult = new MatchingResult (); SecondMatchingResult.setsuccess (เท็จ); // Doreturn (x) เมื่อ (obj). method () หลังจากซ้อนวิธีการหลังจากซ้อนวิธีการโปรแกรมจะส่งคืนค่าที่ระบุตามที่คาดไว้เมื่อดำเนินการวิธีการเหล่านี้ วิธีการที่ไม่ได้ซ้อนจะถูกดำเนินการจะถูกดำเนินการตามเวลาจริง // สอง Doreturns หมายความว่า FirstMatchingResult จะถูกส่งคืนเมื่อ MatchingService.matching เรียกว่าครั้งแรกและ SecondMatchingResult จะถูกส่งคืนเมื่อการโทรครั้งที่สองเรียกว่า // เนื่องจากมีการวนซ้ำใน startBuyProcess Mockito.doreturn (FirstMatchingResult) .doreturn (SecondMatchingResult) เมื่อ (MatchingService). -Matching (Mockito.any (MatchingOrder.class), mockito.any (matchingOrder.class)); MatchingOrder SellOrder = new MatchingOrder (); SellOrder.SetPrice (600); SellOrder.setCount (20); // ซ้อนเมธอด getTopsellorder mockito.doreturn (sellorder) เมื่อ (Matchingservice) .getTopsellorder (mockito.anystring ()); // ซ้อนวิธีการภายนอกที่ขึ้นอยู่กับ Jedis mockito เมื่อ (jedisclient.incrby (mockito.anystring (), mockito.anylong ())). thenreturn (0l); // startBuyProcess เป็นฟังก์ชั่นภายใต้การทดสอบ หากคุณไม่กอง, matchingservice.startbuyprocess (ซื้อ order, true); // การยืนยันการตรวจสอบที่ตามมาคือการทดสอบพฤติกรรมของวิธีการ domatchingsuccess ซึ่งเป็นจุดประสงค์ของการทดสอบนี้ // การตรวจสอบสามารถใช้เพื่อตรวจสอบว่ามีการดำเนินการในคลาสที่แน่นอนกี่ครั้ง? นี่คือการตรวจสอบว่า 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 ()); - การใช้สายลับได้แสดงให้เห็น มาพูดคุยเกี่ยวกับ“ ความละเอียด” ของการทดสอบหน่วยจาก TestStartBuyProcess_incaseofmatchingsuccess
จุดประสงค์ของ TestStartBuyProcess_incaseofMatchingsuccess คือการทดสอบ domatchingsuccess เราทำงานอย่างหนักเพื่อให้เสร็จสิ้นการเตรียมการก่อนหน้านี้ก่อนที่เราจะสามารถทดสอบ domatchingsuccess
แนวปฏิบัติที่ดีกว่าควรเริ่มต้นวิธีการทดสอบใหม่เพื่อทดสอบ domatchingsuccess แยกกันและโฟกัสก็เข้มข้น หลังจาก Domatchingsuccess ถูกเขียนทับแล้ว StartBuyProcess สามารถครอบคลุมสาขาการตัดสินของตัวเองได้ ความครอบคลุมยังคงประสบความสำเร็จและรหัสทดสอบนั้นง่ายต่อการบำรุงรักษา TestStartBuyProcess_incaseofmatchingsuccess ได้รับผลกระทบอย่างง่ายดายจากการเปลี่ยนแปลงเนื่องจากการพิจารณาความรับผิดชอบมากเกินไป การเปลี่ยนแปลงเล็ก ๆ น้อย ๆ อาจส่งผลกระทบต่อการทำงานปกติ
แนะนำกรอบการทดสอบการพึ่งพา Maven
<Ederency> <sderctId> junit </groupId> <ratifactid> Junit </artifactid> <version> 4.11 </เวอร์ชัน> <pope> ทดสอบ </cope> </การพึ่งพาอาศัย> <การพึ่งพา <scope> ทดสอบ </cope> </dercendency> <การพึ่งพา> <roupId> org.springframework </groupId> <ratifactid> การทดสอบฤดูใบไม้ผลิ </artifactid>
การสร้างบริบทของ Springboot+Junit+Mockito
mockitobasedtest
@runwith (springjunit4classrunner.class) @springapplicationconfiguration (คลาส = testapplication.class) คลาสนามธรรมนามธรรม mockitobasedtest {@before public void setup () โยนข้อยกเว้น {// เริ่มต้นวัตถุจำลองทั้งหมด }} // คลาสทดสอบอื่น ๆ สืบทอด mockitobasedtest ข้างต้นเป็นเนื้อหาทั้งหมดของบทความนี้ ฉันหวังว่ามันจะเป็นประโยชน์ต่อการเรียนรู้ของทุกคนและฉันหวังว่าทุกคนจะสนับสนุน wulin.com มากขึ้น