ด้วยความก้าวหน้าของเทคโนโลยีและอุตสาหกรรมที่เปลี่ยนจากแบบจำลอง Waterfall เป็น Agile และตอนนี้ไปสู่ DevOps การเปลี่ยนแปลงและการปรับปรุงในแอปพลิเคชันจะถูกนำไปใช้กับการผลิตในนาทีที่เกิดขึ้น เมื่อโค้ดถูกนำไปใช้งานจริงอย่างรวดเร็วเราจึงต้องมั่นใจว่าการเปลี่ยนแปลงของเราได้ผลและไม่ทำลายฟังก์ชันการทำงานที่มีมาก่อน
เพื่อสร้างความมั่นใจนี้เราต้องมี กรอบ สำหรับการทดสอบการถดถอยอัตโนมัติ สำหรับการทดสอบการถดถอยมีการทดสอบมากมายที่ควรดำเนินการจากมุมมองระดับ API แต่ในที่นี้เราจะกล่าวถึงการทดสอบหลัก 2 ประเภทดังนี้
มีกรอบมากมายสำหรับทุกภาษาการเขียนโปรแกรม เราจะเน้นไปที่การเขียนหน่วยและการทดสอบการรวมสำหรับเว็บแอปที่เขียน Java กรอบฤดูใบไม้ผลิ
แผนภูมิเปรียบเทียบซอฟต์แวร์การจัดการโครงการ
โดยส่วนใหญ่เราจะเขียนวิธีการในชั้นเรียนและสิ่งเหล่านี้จะโต้ตอบกับเมธอดของคลาสอื่น ๆ ในโลกปัจจุบันโดยเฉพาะอย่างยิ่งใน แอปพลิเคชันระดับองค์กร - ความซับซ้อนของแอปพลิเคชันคือเมธอดเดียวอาจเรียกมากกว่าหนึ่งวิธีของหลายคลาส ดังนั้นเมื่อเขียนการทดสอบหน่วยสำหรับวิธีดังกล่าวเราจำเป็นต้องมีวิธีส่งคืนข้อมูลจำลองจากการเรียกเหล่านั้น เนื่องจากจุดประสงค์ของการทดสอบหน่วยนี้คือการทดสอบเพียงวิธีเดียวไม่ใช่การเรียกทั้งหมดที่วิธีการนี้ทำขึ้น
มาเริ่มการทดสอบหน่วย Java ในฤดูใบไม้ผลิโดยใช้กรอบงาน JUnit เราจะเริ่มจากสิ่งที่คุณอาจเคยได้ยินนั่นคือการล้อเลียน
สมมติว่าคุณมีคลาส CalculateArea
ซึ่งมีฟังก์ชัน calculateArea(Type type, Double... args)
ซึ่งคำนวณพื้นที่ของรูปร่างของประเภทที่กำหนด (วงกลมสี่เหลี่ยมจัตุรัสหรือสี่เหลี่ยมผืนผ้า)
รหัสมีลักษณะเช่นนี้ในแอปพลิเคชันปกติซึ่งไม่ใช้การฉีดขึ้นต่อกัน:
public class CalculateArea { SquareService squareService; RectangleService rectangleService; CircleService circleService; CalculateArea(SquareService squareService, RectangleService rectangeService, CircleService circleService) { this.squareService = squareService; this.rectangleService = rectangeService; this.circleService = circleService; } public Double calculateArea(Type type, Double... r ) { switch (type) { case RECTANGLE: if(r.length >=2) return rectangleService.area(r[0],r[1]); else throw new RuntimeException('Missing required params'); case SQUARE: if(r.length >=1) return squareService.area(r[0]); else throw new RuntimeException('Missing required param'); case CIRCLE: if(r.length >=1) return circleService.area(r[0]); else throw new RuntimeException('Missing required param'); default: throw new RuntimeException('Operation not supported'); } } }
public class SquareService { public Double area(double r) { return r * r; } }
public class RectangleService { public Double area(Double r, Double h) { return r * h; } }
public class CircleService { public Double area(Double r) { return Math.PI * r * r; } }
public enum Type { RECTANGLE,SQUARE,CIRCLE; }
ตอนนี้ถ้าเราต้องการทดสอบหน่วยฟังก์ชัน calculateArea()
ของชั้นเรียน CalculateArea
ดังนั้นแรงจูงใจของเราควรตรวจสอบว่า switch
กรณีและเงื่อนไขข้อยกเว้นทำงาน เราไม่ควรทดสอบว่าบริการรูปร่างส่งคืนค่าที่ถูกต้องหรือไม่เพราะตามที่กล่าวไว้ก่อนหน้านี้แรงจูงใจของการทดสอบหน่วยฟังก์ชันคือการทดสอบตรรกะของฟังก์ชันไม่ใช่ตรรกะของการเรียกใช้ฟังก์ชัน
ดังนั้นเราจะจำลองค่าที่ส่งคืนโดยฟังก์ชันบริการแต่ละรายการ (เช่น rectangleService.area()
และทดสอบฟังก์ชันการโทร (เช่น CalculateArea.calculateArea()
) ตามค่าที่เยาะเย้ยเหล่านั้น
กรณีทดสอบง่ายๆสำหรับบริการสี่เหลี่ยมผืนผ้า - ทดสอบว่า calculateArea()
โทรจริง rectangleService.area()
ด้วยพารามิเตอร์ที่ถูกต้อง - จะมีลักษณะดังนี้:
import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.mockito.Mockito; public class CalculateAreaTest { RectangleService rectangleService; SquareService squareService; CircleService circleService; CalculateArea calculateArea; @Before public void init() { rectangleService = Mockito.mock(RectangleService.class); squareService = Mockito.mock(SquareService.class); circleService = Mockito.mock(CircleService.class); calculateArea = new CalculateArea(squareService,rectangleService,circleService); } @Test public void calculateRectangleAreaTest() { Mockito.when(rectangleService.area(5.0d,4.0d)).thenReturn(20d); Double calculatedArea = this.calculateArea.calculateArea(Type.RECTANGLE, 5.0d, 4.0d); Assert.assertEquals(new Double(20d),calculatedArea); } }
สองบรรทัดหลักที่ควรทราบ ได้แก่ :
rectangleService = Mockito.mock(RectangleService.class);
- สิ่งนี้ทำให้เกิดการเยาะเย้ยซึ่งไม่ใช่วัตถุจริง แต่เป็นการล้อเลียนMockito.when(rectangleService.area(5.0d,4.0d)).thenReturn(20d);
- สิ่งนี้กล่าวว่าเมื่อถูกล้อเลียนและ rectangleService
วัตถุ area
เรียกวิธีการด้วยพารามิเตอร์ที่ระบุจากนั้นส่งคืน 20d
ตอนนี้จะเกิดอะไรขึ้นเมื่อโค้ดด้านบนเป็นส่วนหนึ่งของแอปพลิเคชัน Spring
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component public class CalculateArea { SquareService squareService; RectangleService rectangleService; CircleService circleService; public CalculateArea(@Autowired SquareService squareService, @Autowired RectangleService rectangeService, @Autowired CircleService circleService) { this.squareService = squareService; this.rectangleService = rectangeService; this.circleService = circleService; } public Double calculateArea(Type type, Double... r ) { // (same implementation as before) } }
ที่นี่เรามีคำอธิบายประกอบสองรายการสำหรับ Spring framework ที่เป็นพื้นฐานเพื่อตรวจจับในเวลาเริ่มต้นบริบท:
@Component
: สร้างชนิดของถั่ว CalculateArea
@Autowired
: ค้นหาถั่ว rectangleService
, squareService
และ circleService
แล้วฉีดเข้าไปในถั่ว calculatedArea
ในทำนองเดียวกันเราสร้างถั่วสำหรับคลาสอื่น ๆ ด้วย:
import org.springframework.stereotype.Service; @Service public class SquareService { public Double area(double r) { return r*r; } }
import org.springframework.stereotype.Service; @Service public class CircleService { public Double area(Double r) { return Math.PI * r * r; } }
import org.springframework.stereotype.Service; @Service public class RectangleService { public Double area(Double r, Double h) { return r*h; } }
ตอนนี้ถ้าเราเรียกใช้การทดสอบผลลัพธ์จะเหมือนกัน เราใช้การฉีดตัวสร้างที่นี่และโชคดีที่ไม่ต้องเปลี่ยนกรณีทดสอบของเรา
แต่มีอีกวิธีหนึ่งในการฉีดถั่วของรูปสี่เหลี่ยมจัตุรัสวงกลมและสี่เหลี่ยมผืนผ้า: การฉีดสนาม หากเราใช้สิ่งนั้นกรณีทดสอบของเราจะต้องมีการเปลี่ยนแปลงเล็กน้อย
เราจะไม่พูดถึงกลไกการฉีดแบบใดที่ดีกว่าเนื่องจากไม่ได้อยู่ในขอบเขตของบทความ แต่เราสามารถพูดได้ว่า: ไม่ว่าคุณจะใช้กลไกแบบใดในการฉีดถั่วก็มีวิธีเขียนการทดสอบ JUnit เสมอ
ในกรณีของการแทรกฟิลด์รหัสจะมีลักษณะดังนี้:
@Component public class CalculateArea { @Autowired SquareService squareService; @Autowired RectangleService rectangleService; @Autowired CircleService circleService; public Double calculateArea(Type type, Double... r ) { // (same implementation as before) } }
หมายเหตุ: เนื่องจากเราใช้การแทรกฟิลด์จึงไม่จำเป็นต้องมีคอนสตรัคเตอร์ที่กำหนดพารามิเตอร์ดังนั้นอ็อบเจ็กต์จึงถูกสร้างขึ้นโดยใช้ค่าเริ่มต้นและค่าจะถูกกำหนดโดยใช้กลไกการแทรกฟิลด์
รหัสสำหรับคลาสบริการของเรายังคงเหมือนเดิม แต่รหัสสำหรับคลาสทดสอบมีดังนี้:
public class CalculateAreaTest { @Mock RectangleService rectangleService; @Mock SquareService squareService; @Mock CircleService circleService; @InjectMocks CalculateArea calculateArea; @Before public void init() { MockitoAnnotations.initMocks(this); } @Test public void calculateRectangleAreaTest() { Mockito.when(rectangleService.area(5.0d,4.0d)).thenReturn(20d); Double calculatedArea = this.calculateArea.calculateArea(Type.RECTANGLE, 5.0d, 4.0d); Assert.assertEquals(new Double(20d),calculatedArea); } }
มีบางสิ่งที่แตกต่างกันที่นี่: ไม่ใช่พื้นฐาน แต่เป็นวิธีที่เราบรรลุเป้าหมาย
ประการแรกวิธีที่เราล้อเลียนวัตถุของเรา: เราใช้ @Mock
คำอธิบายประกอบพร้อมด้วย initMocks()
เพื่อสร้างล้อเลียน ประการที่สองเราฉีด mocks ลงในวัตถุจริงโดยใช้ @InjectMocks
พร้อมด้วย initMocks()
.
นี่เป็นเพียงการลดจำนวนบรรทัดของโค้ด
ในตัวอย่างข้างต้นนักวิ่งขั้นพื้นฐานที่ใช้ในการทดสอบทั้งหมดคือ BlockJUnit4ClassRunner
ซึ่งตรวจจับคำอธิบายประกอบทั้งหมดและเรียกใช้การทดสอบทั้งหมดตามนั้น
หากเราต้องการฟังก์ชันเพิ่มเติมเราอาจเขียนนักวิ่งที่กำหนดเอง ตัวอย่างเช่นในคลาสทดสอบข้างต้นหากเราต้องการข้ามบรรทัด MockitoAnnotations.initMocks(this);
จากนั้นเราสามารถใช้นักวิ่งอื่นที่สร้างขึ้นจาก BlockJUnit4ClassRunner
เช่น MockitoJUnitRunner
.
การใช้ MockitoJUnitRunner
เราไม่จำเป็นต้องเริ่มต้นล้อเลียนและฉีดมันด้วยซ้ำ ซึ่งจะทำได้โดย MockitoJUnitRunner
เพียงแค่อ่านคำอธิบายประกอบ
(นอกจากนี้ยังมี SpringJUnit4ClassRunner
ซึ่งเริ่มต้น ApplicationContext
ที่จำเป็นสำหรับการทดสอบการรวม Spring เช่นเดียวกับ ApplicationContext
ที่สร้างขึ้นเมื่อแอปพลิเคชัน Spring เริ่มต้นซึ่งเราจะกล่าวถึงในภายหลัง)
เมื่อเราต้องการให้ออบเจ็กต์ในคลาสทดสอบล้อเลียนเมธอดบางอย่าง แต่ยังเรียกเมธอดจริงบางอย่างเราก็จำเป็นต้องมีการเยาะเย้ยบางส่วน สิ่งนี้ทำได้โดย @Spy
ใน JUnit
ไม่เหมือนกับการใช้ @Mock
ร่วมกับ @Spy
วัตถุจริงจะถูกสร้างขึ้น แต่วิธีการของวัตถุนั้นสามารถล้อเลียนหรือเรียกได้ว่าเป็นอะไรก็ได้ที่เราต้องการ
ตัวอย่างเช่นถ้า area
วิธีการในคลาส RectangleService
เรียกวิธีพิเศษ log()
และเราต้องการพิมพ์บันทึกนั้นจริงๆจากนั้นรหัสจะเปลี่ยนเป็นดังนี้:
@Service public class RectangleService { public Double area(Double r, Double h) { log(); return r*h; } public void log() { System.out.println('skip this'); } }
ถ้าเราเปลี่ยน @Mock
คำอธิบายประกอบของ rectangleService
เป็น @Spy
และทำการเปลี่ยนแปลงโค้ดบางอย่างตามที่แสดงด้านล่างจากนั้นในผลลัพธ์เราจะเห็นการพิมพ์บันทึก แต่วิธีการ area()
จะถูกล้อเลียน นั่นคือฟังก์ชันดั้งเดิมถูกเรียกใช้เพื่อผลข้างเคียงเท่านั้น ค่าที่ส่งคืนจะถูกแทนที่ด้วยค่าที่ถูกเยาะเย้ย
@RunWith(MockitoJUnitRunner.class) public class CalculateAreaTest { @Spy RectangleService rectangleService; @Mock SquareService squareService; @Mock CircleService circleService; @InjectMocks CalculateArea calculateArea; @Test public void calculateRectangleAreaTest() { Mockito.doCallRealMethod().when(rectangleService).log(); Mockito.when(rectangleService.area(5.0d,4.0d)).thenReturn(20d); Double calculatedArea = this.calculateArea.calculateArea(Type.RECTANGLE, 5.0d, 4.0d); Assert.assertEquals(new Double(20d),calculatedArea); } }
Controller
หรือ RequestHandler
?จากสิ่งที่เราเรียนรู้ข้างต้นรหัสทดสอบของคอนโทรลเลอร์สำหรับตัวอย่างของเราจะเป็นดังนี้:
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; @Controller public class AreaController { @Autowired CalculateArea calculateArea; @RequestMapping(value = 'api/area', method = RequestMethod.GET) @ResponseBody public ResponseEntity calculateArea( @RequestParam('type') String type, @RequestParam('param1') String param1, @RequestParam(value = 'param2', required = false) String param2 ) { try { Double area = calculateArea.calculateArea( Type.valueOf(type), Double.parseDouble(param1), Double.parseDouble(param2) ); return new ResponseEntity(area, HttpStatus.OK); } catch (Exception e) { return new ResponseEntity(e.getCause(), HttpStatus.INTERNAL_SERVER_ERROR); } } }
import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.junit.MockitoJUnitRunner; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @RunWith(MockitoJUnitRunner.class) public class AreaControllerTest { @Mock CalculateArea calculateArea; @InjectMocks AreaController areaController; @Test public void calculateAreaTest() { Mockito .when(calculateArea.calculateArea(Type.RECTANGLE,5.0d, 4.0d)) .thenReturn(20d); ResponseEntity responseEntity = areaController.calculateArea('RECTANGLE', '5', '4'); Assert.assertEquals(HttpStatus.OK,responseEntity.getStatusCode()); Assert.assertEquals(20d,responseEntity.getBody()); } }
เมื่อดูรหัสทดสอบคอนโทรลเลอร์ด้านบนก็ใช้งานได้ดี แต่มีปัญหาพื้นฐานอย่างหนึ่ง: ทดสอบเฉพาะการเรียกใช้เมธอดเท่านั้นไม่ใช่การเรียก API จริง กรณีทดสอบทั้งหมดที่พารามิเตอร์ API และสถานะของการเรียก API จำเป็นต้องทดสอบสำหรับอินพุตที่แตกต่างกันหายไป
รหัสนี้ดีกว่า:
import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.Mockito; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standaloneSetup; @RunWith(SpringJUnit4ClassRunner.class) public class AreaControllerTest { @Mock CalculateArea calculateArea; @InjectMocks AreaController areaController; MockMvc mockMvc; @Before public void init() { mockMvc = standaloneSetup(areaController).build(); } @Test public void calculateAreaTest() throws Exception { Mockito .when(calculateArea.calculateArea(Type.RECTANGLE,5.0d, 4.0d)) .thenReturn(20d); mockMvc.perform( MockMvcRequestBuilders.get('/api/area?type=RECTANGLE¶m1=5¶m2=4') ) .andExpect(status().isOk()) .andExpect(content().string('20.0')); } }
ที่นี่เราสามารถดูวิธี MockMvc
รับหน้าที่เรียก API จริง นอกจากนี้ยังมีผู้จับคู่พิเศษเช่น status()
และ content()
ซึ่งทำให้ง่ายต่อการตรวจสอบเนื้อหา
ตอนนี้เรารู้แล้วว่าแต่ละหน่วยของโค้ดทำงานได้แล้วตรวจสอบให้แน่ใจว่าพวกเขาโต้ตอบกันตามที่เราคาดหวัง
ขั้นแรกเราต้องสร้างอินสแตนซ์ของถั่วทั้งหมดซึ่งเป็นสิ่งเดียวกับที่เกิดขึ้นในช่วงเวลาของการเริ่มต้นบริบท Spring ระหว่างการเริ่มต้นแอปพลิเคชัน
สำหรับสิ่งนี้เรากำหนดถั่วทั้งหมดในชั้นเรียนสมมติว่า TestConfig.java
:
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class TestConfig { @Bean public AreaController areaController() { return new AreaController(); } @Bean public CalculateArea calculateArea() { return new CalculateArea(); } @Bean public RectangleService rectangleService() { return new RectangleService(); } @Bean public SquareService squareService() { return new SquareService(); } @Bean public CircleService circleService() { return new CircleService(); } }
ตอนนี้เรามาดูกันว่าเราใช้คลาสนี้อย่างไรและเขียนแบบทดสอบบูรณาการ:
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standaloneSetup; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = {TestConfig.class}) public class AreaControllerIntegrationTest { @Autowired AreaController areaController; MockMvc mockMvc; @Before public void init() { mockMvc = standaloneSetup(areaController).build(); } @Test public void calculateAreaTest() throws Exception { mockMvc.perform( MockMvcRequestBuilders.get('/api/area?type=RECTANGLE¶m1=5¶m2=4') ) .andExpect(status().isOk()) .andExpect(content().string('20.0')); } }
มีการเปลี่ยนแปลงบางอย่างที่นี่:
@ContextConfiguration(classes = {TestConfig.class})
- สิ่งนี้จะบอกกรณีทดสอบที่มีคำจำกัดความของ bean ทั้งหมดอยู่@InjectMocks
เราใช้: @Autowired AreaController areaController;
อย่างอื่นยังคงเหมือนเดิม หากเราดีบักการทดสอบเราจะเห็นว่าโค้ดทำงานจนถึงบรรทัดสุดท้ายของ area()
วิธีการใน RectangleService
ที่ไหน return r*h
คำนวณ กล่าวอีกนัยหนึ่งตรรกะทางธุรกิจที่แท้จริงทำงาน
นี่ไม่ได้หมายความว่าไม่มีการเยาะเย้ยการเรียกเมธอดหรือการเรียกฐานข้อมูลที่มีอยู่ในการทดสอบการรวม ในตัวอย่างข้างต้นไม่มีการใช้บริการหรือฐานข้อมูลของบุคคลที่สามดังนั้นเราจึงไม่จำเป็นต้องใช้ล้อเลียน ในชีวิตจริงแอปพลิเคชันดังกล่าวหายากและเรามักจะโดนฐานข้อมูลหรือ API ของบุคคลที่สามหรือทั้งสองอย่าง ในกรณีนี้เมื่อเราสร้าง bean ใน TestConfig
คลาสเราไม่ได้สร้างออบเจ็กต์จริง แต่เป็นวัตถุจำลองและใช้มันทุกที่ที่ต้องการ
บ่อยครั้งสิ่งที่หยุดยั้งนักพัฒนาส่วนหลังในการเขียนหน่วยหรือการทดสอบการรวมก็คือข้อมูลการทดสอบที่เราต้องเตรียมสำหรับการทดสอบทุกครั้ง
โดยปกติหากข้อมูลมีขนาดเล็กพอโดยมีตัวแปรหนึ่งหรือสองตัวก็ทำได้ง่ายเพียงแค่สร้างออบเจ็กต์ของคลาสข้อมูลทดสอบและกำหนดค่าบางอย่าง
ตัวอย่างเช่นหากเราคาดหวังว่าวัตถุจำลองจะส่งคืนวัตถุอื่นเมื่อมีการเรียกใช้ฟังก์ชันบนวัตถุจำลองเราจะทำสิ่งนี้:
Class1 object = new Class1(); object.setVariable1(1); object.setVariable2(2);
จากนั้นในการใช้วัตถุนี้เราจะทำสิ่งนี้:
Mockito.when(service.method(arguments...)).thenReturn(object);
นี่ใช้ได้ดีในตัวอย่าง JUnit ด้านบน แต่เมื่อตัวแปรสมาชิกในข้างต้น Class1
ชั้นเรียนเพิ่มขึ้นเรื่อย ๆ จากนั้นการตั้งค่าแต่ละฟิลด์จะกลายเป็นความเจ็บปวด บางครั้งมันอาจเกิดขึ้นที่คลาสมีสมาชิกคลาสอื่นที่ไม่ใช่คลาสดั้งเดิมกำหนดไว้ จากนั้นการสร้างออบเจ็กต์ของคลาสนั้นและการตั้งค่าฟิลด์ที่จำเป็นแต่ละฟิลด์จะช่วยเพิ่มความพยายามในการพัฒนาเพื่อให้บรรลุผลสำเร็จบางอย่าง
วิธีแก้ปัญหาคือสร้างสคีมา JSON ของคลาสด้านบนและเพิ่มข้อมูลที่เกี่ยวข้องในไฟล์ JSON หนึ่งครั้ง ตอนนี้อยู่ในชั้นทดสอบที่เราสร้าง Class1
วัตถุเราไม่จำเป็นต้องสร้างวัตถุด้วยตนเอง เราอ่านไฟล์ JSON แทนและโดยใช้ ObjectMapper
แมปลงในไฟล์ที่จำเป็น Class1
ชั้น:
ObjectMapper objectMapper = new ObjectMapper(); Class1 object = objectMapper.readValue( new String(Files.readAllBytes( Paths.get('src/test/resources/'+fileName)) ), Class1.class );
นี่เป็นความพยายามเพียงครั้งเดียวในการสร้างไฟล์ JSON และเพิ่มค่าให้กับไฟล์ การทดสอบใหม่ใด ๆ หลังจากนั้นสามารถใช้สำเนาของไฟล์ JSON ที่มีการเปลี่ยนแปลงฟิลด์ตามความต้องการของการทดสอบใหม่
เป็นที่ชัดเจนว่ามีหลายวิธีในการเขียนการทดสอบหน่วย Java ขึ้นอยู่กับวิธีที่เราเลือกฉีดถั่ว น่าเสียดายที่บทความส่วนใหญ่ในหัวข้อนี้มักจะคิดว่ามีเพียงวิธีเดียวดังนั้นจึงสับสนได้ง่ายโดยเฉพาะอย่างยิ่งเมื่อทำงานกับโค้ดที่เขียนขึ้นภายใต้สมมติฐานอื่น หวังว่าแนวทางของเราจะช่วยให้นักพัฒนาซอฟต์แวร์ประหยัดเวลาในการหาวิธีล้อเลียนที่ถูกต้องและควรใช้นักวิ่งทดสอบตัวใด
โดยไม่คำนึงถึงภาษาหรือเฟรมเวิร์กที่เราใช้ - อาจเป็นเวอร์ชันใหม่ของ Spring หรือ JUnit ก็ตาม - ฐานแนวคิดยังคงเหมือนเดิมตามที่อธิบายไว้ในบทแนะนำ JUnit ข้างต้น ขอให้สนุกกับการทดสอบ!
JUnit เป็นเฟรมเวิร์กที่มีชื่อเสียงที่สุดสำหรับการเขียนการทดสอบหน่วยใน Java คุณเขียนวิธีการทดสอบที่เรียกใช้วิธีการจริงที่จะทดสอบ กรณีทดสอบจะตรวจสอบลักษณะการทำงานของโค้ดโดยยืนยันค่าที่ส่งคืนกับค่าที่คาดไว้โดยกำหนดพารามิเตอร์ที่ส่งผ่าน
นักพัฒนา Java ส่วนใหญ่ยอมรับว่า JUnit เป็นกรอบการทดสอบหน่วยที่ดีที่สุด เป็นมาตรฐานโดยพฤตินัยตั้งแต่ปี 1997 และแน่นอนว่าได้รับการสนับสนุนจำนวนมากที่สุดเมื่อเทียบกับเฟรมเวิร์กการทดสอบหน่วย Java อื่น ๆ
ในการทดสอบหน่วยแต่ละหน่วย (โดยปกติวิธีการของวัตถุถือเป็น 'หน่วย') จะถูกทดสอบในรูปแบบอัตโนมัติ
การทดสอบ JUnit ใช้เพื่อทดสอบพฤติกรรมของเมธอดในคลาสที่เราเขียน เราทดสอบวิธีการเพื่อให้ได้ผลลัพธ์ที่คาดหวังและในบางครั้งกรณีที่มีข้อยกเว้น - ว่าวิธีนี้สามารถจัดการกับข้อยกเว้นในแบบที่เราต้องการได้หรือไม่
JUnit เป็นเฟรมเวิร์กที่มีคลาสและวิธีการต่างๆมากมายในการเขียนแบบทดสอบหน่วยอย่างง่ายดาย
การปรับประสิทธิภาพของฐานข้อมูลคืออะไร
ใช่ JUnit เป็นโครงการโอเพ่นซอร์สซึ่งดูแลโดยนักพัฒนาที่ใช้งานอยู่หลายคน
JUnit ลดมาตรฐานสำเร็จรูปที่นักพัฒนาต้องใช้เมื่อเขียนการทดสอบหน่วย
Kent Beck และ Erich Gamma เริ่มสร้าง JUnit ปัจจุบันโครงการโอเพนซอร์สมีผู้ร่วมให้ข้อมูลมากกว่าร้อยคน