- การทดสอบการรวมฐานข้อมูลโดยใช้ MariaDB เพื่อแทนที่ MySql
- การดำเนินการแอปพลิเคชันหลายภาษา
- การบันทึกไฟล์ลงในแอปพลิเคชันและข้อมูลเกี่ยวกับไฟล์เหล่านั้นลงในฐานข้อมูล
ประเภทของการทดสอบ
การทดสอบคืออะไร? ดังที่ Wiki กล่าวไว้: “ การทดสอบหรือการทดสอบเป็นวิธีการศึกษากระบวนการพื้นฐานของระบบโดยการวางระบบในสถานการณ์ที่แตกต่างกันและติดตามการเปลี่ยนแปลงที่สังเกตได้” กล่าวอีกนัยหนึ่ง นี่คือการทดสอบการทำงานที่ถูกต้องของระบบของเราในบางสถานการณ์-
การทดสอบหน่วยคือการทดสอบที่มีหน้าที่ทดสอบแต่ละโมดูลของระบบแยกกัน เป็นที่พึงประสงค์ว่าสิ่งเหล่านี้เป็นส่วนที่แบ่งได้น้อยที่สุดของระบบ เช่น โมดูล
-
การทดสอบระบบเป็นการทดสอบระดับสูงเพื่อทดสอบการทำงานของแอปพลิเคชันชิ้นใหญ่หรือระบบโดยรวม
-
การทดสอบการถดถอยคือการทดสอบที่ใช้ในการตรวจสอบว่าคุณลักษณะใหม่หรือการแก้ไขข้อบกพร่องส่งผลต่อฟังก์ชันการทำงานที่มีอยู่ของแอปพลิเคชันหรือไม่ และข้อบกพร่องเก่าปรากฏขึ้นอีกครั้งหรือไม่
-
การทดสอบฟังก์ชันคือการตรวจสอบความสอดคล้องของส่วนหนึ่งของแอปพลิเคชันตามข้อกำหนดที่ระบุไว้ในข้อมูลจำเพาะ เรื่องราวของผู้ใช้ ฯลฯ
ประเภทของการทดสอบการทำงาน:
- การทดสอบ "กล่องสีขาว"สำหรับการปฏิบัติตามส่วนหนึ่งของแอปพลิเคชันด้วยข้อกำหนดที่มีความรู้เกี่ยวกับการใช้งานระบบภายใน
- การทดสอบ "กล่องดำ"สำหรับการปฏิบัติตามส่วนหนึ่งของแอปพลิเคชันโดยปราศจากความรู้เกี่ยวกับการใช้งานระบบภายใน
- การทดสอบประสิทธิภาพคือการทดสอบประเภทหนึ่งที่เขียนขึ้นเพื่อกำหนดความเร็วที่ระบบหรือส่วนหนึ่งของระบบทำงานภายใต้ภาระงานที่กำหนด
- การทดสอบโหลด - การทดสอบที่ออกแบบมาเพื่อตรวจสอบความเสถียรของระบบภายใต้โหลดมาตรฐาน และเพื่อค้นหาจุดสูงสุดที่เป็นไปได้ที่แอปพลิเคชันทำงานอย่างถูกต้อง
- การทดสอบภาวะวิกฤตเป็นการทดสอบประเภทหนึ่งที่ออกแบบมาเพื่อตรวจสอบการทำงานของแอปพลิเคชันภายใต้โหลดที่ไม่ได้มาตรฐาน และเพื่อกำหนดจุดสูงสุดที่เป็นไปได้ที่ระบบจะไม่ขัดข้อง
- การทดสอบ ความปลอดภัย - การทดสอบที่ใช้เพื่อตรวจสอบความปลอดภัยของระบบ (จากการโจมตีของแฮกเกอร์ ไวรัส การเข้าถึงข้อมูลที่เป็นความลับโดยไม่ได้รับอนุญาต และความสุขอื่น ๆ ของชีวิต)
- การทดสอบการแปลคือการทดสอบการแปลสำหรับแอปพลิเคชัน
- การทดสอบการใช้งานคือการทดสอบประเภทหนึ่งที่มุ่งตรวจสอบการใช้งาน ความเข้าใจ ความน่าดึงดูดใจ และความสามารถในการเรียนรู้ของผู้ใช้ ทั้งหมดนี้ฟังดูดี แต่ในทางปฏิบัติมันทำงานอย่างไร? ง่ายมาก: ใช้ปิรามิดทดสอบของ Mike Cohn:
-
หน่วย - การทดสอบหน่วยที่ใช้ในเลเยอร์ต่างๆ ของแอปพลิเคชัน ทดสอบตรรกะที่หารน้อยที่สุดของแอปพลิเคชัน เช่น คลาส แต่ส่วนใหญ่มักจะเป็นวิธีการ การทดสอบเหล่านี้มักจะพยายามแยกออกจากตรรกะภายนอกให้มากที่สุดเท่าที่จะเป็นไปได้ นั่นคือเพื่อสร้างภาพลวงตาว่าแอปพลิเคชันที่เหลือทำงานในโหมดมาตรฐาน
ควรมีการทดสอบเหล่านี้เป็นจำนวนมาก (มากกว่าประเภทอื่นๆ) เนื่องจากเป็นการทดสอบชิ้นเล็กๆ และมีน้ำหนักเบามาก ไม่ใช้ทรัพยากรมากนัก (โดยทรัพยากร ฉันหมายถึง RAM และเวลา)
-
บูรณาการ - การทดสอบบูรณาการ จะตรวจสอบชิ้นส่วนที่ใหญ่กว่าของระบบ กล่าวคือ เป็นการรวมกันของตรรกะหลายส่วน (วิธีการหรือคลาสหลายวิธี) หรือความถูกต้องของการทำงานกับส่วนประกอบภายนอก โดยปกติแล้วจะมีการทดสอบเหล่านี้น้อยกว่าการทดสอบหน่วยเนื่องจากมีน้ำหนักมากกว่า
เป็นตัวอย่างการทดสอบการรวม คุณสามารถพิจารณาเชื่อมต่อกับฐานข้อมูลและตรวจสอบการดำเนินการที่ถูกต้องของวิธีการทำงานกับฐานข้อมูล
-
UI - การทดสอบที่ตรวจสอบการทำงานของส่วนต่อประสานผู้ใช้ สิ่งเหล่านี้ส่งผลต่อตรรกะในทุกระดับของแอปพลิเคชัน ซึ่งเป็นสาเหตุที่เรียกว่า end-to-end ตามกฎแล้วมีจำนวนน้อยกว่ามาก ดังนั้นจึงเป็นเส้นทางที่หนักที่สุดและต้องตรวจสอบเส้นทางที่จำเป็น (ใช้) มากที่สุด
ในรูปด้านบน เราจะเห็นอัตราส่วนของพื้นที่ของส่วนต่างๆ ของรูปสามเหลี่ยม: สัดส่วนที่เท่ากันโดยประมาณจะคงอยู่ในจำนวนการทดสอบเหล่านี้ในการทำงานจริง
วันนี้เราจะมาดูรายละเอียดการทดสอบที่ใช้มากที่สุด - การทดสอบหน่วย เนื่องจากนักพัฒนา Java ที่เคารพตนเองทุกคนควรจะสามารถใช้งานได้ในระดับพื้นฐาน
- เนื้อหาเกี่ยวกับ Code Coverage บนJavaRushและHabré ;
- ทฤษฎีการทดสอบพื้นฐาน
- เรากำลังเขียนแบบทดสอบของเรา
- เราทำการทดสอบไม่ว่าจะผ่านหรือไม่ (เราเห็นว่าทุกอย่างเป็นสีแดง - อย่าเพิ่งตกใจ: ควรจะเป็นแบบนี้)
- เราเพิ่มโค้ดที่ควรเป็นไปตามการทดสอบนี้ (รันการทดสอบ)
- เราปรับโครงสร้างโค้ดใหม่
- การระบุข้อมูลที่จะทดสอบ (ฟิกซ์เจอร์)
- การใช้โค้ดภายใต้การทดสอบ (การเรียกวิธีการภายใต้การทดสอบ)
- ตรวจสอบผลลัพธ์และเปรียบเทียบกับผลลัพธ์ที่คาดหวัง
assertEquals(Object expecteds, Object actuals)
— ตรวจสอบว่าวัตถุที่ส่งเท่ากันหรือไม่assertTrue(boolean flag)
- ตรวจสอบว่าค่าที่ส่งคืนค่าจริงหรือไม่assertFalse(boolean flag)
- ตรวจสอบว่าค่าที่ส่งคืนค่าเท็จหรือไม่assertNull(Object object)
– ตรวจสอบว่าวัตถุนั้นเป็นโมฆะหรือไม่assertSame(Object firstObject, Object secondObject)
— ตรวจสอบว่าค่าที่ส่งผ่านอ้างถึงวัตถุเดียวกันหรือไม่assertThat(T t, Matcher<T> matcher)
— ตรวจสอบว่าเป็นไปตามเงื่อนไขที่ระบุในตัวจับคู่หรือไม่

แนวคิดหลักของการทดสอบหน่วย
ความครอบคลุมการทดสอบ (Code Coverage) เป็นหนึ่งในการประเมินคุณภาพการทดสอบแอปพลิเคชันหลัก นี่คือเปอร์เซ็นต์ของโค้ดที่ครอบคลุมโดยการทดสอบ (0-100%) ในทางปฏิบัติ หลายๆ คนไล่ตามเปอร์เซ็นต์นี้ ซึ่งฉันไม่เห็นด้วย เนื่องจากพวกเขาเริ่มเพิ่มการทดสอบในส่วนที่ไม่จำเป็น ตัวอย่างเช่น บริการของเรามีการดำเนินการ CRUD มาตรฐาน (สร้าง/รับ/อัปเดต/ลบ) โดยไม่มีตรรกะเพิ่มเติม วิธีการเหล่านี้เป็นเพียงตัวกลางที่มอบหมายงานให้กับเลเยอร์ที่ทำงานกับพื้นที่เก็บข้อมูลเท่านั้น ในสถานการณ์นี้ เราไม่มีอะไรต้องทดสอบ: บางทีวิธีนี้จะเรียกวิธีการจากเต่าหรือไม่ แต่ก็ไม่ร้ายแรง เพื่อประเมินความครอบคลุมของการทดสอบ มักจะใช้เครื่องมือเพิ่มเติม: JaCoCo, Cobertura, Clover, Emma เป็นต้น หากต้องการศึกษาปัญหานี้อย่างละเอียด โปรดเก็บบทความที่เหมาะสมไว้ 2-3 บทความ:
ขั้นตอนการทดสอบ
การทดสอบประกอบด้วยสามขั้นตอน:
สภาพแวดล้อมการทดสอบ
ตอนนี้เรามาลงมือทำธุรกิจกันดีกว่า มีสภาพแวดล้อมการทดสอบ (เฟรมเวิร์ก) มากมายสำหรับ Java ที่ได้รับความนิยมมากที่สุดคือ JUnit และ TestNG สำหรับการทบทวนของเรา เราใช้:
assertThat(firstObject).isEqualTo(secondObject)
ที่นี่ฉันได้พูดถึงวิธีการพื้นฐานแล้ว เนื่องจากส่วนที่เหลือเป็นรูปแบบที่แตกต่างกันไปจากที่กล่าวมาข้างต้น
การทดสอบการปฏิบัติ
ตอนนี้เรามาดูเนื้อหาข้างต้นโดยใช้ตัวอย่างที่เฉพาะเจาะจง เราจะทดสอบวิธีการใช้บริการ - อัปเดต เราจะไม่พิจารณาชั้น dao เนื่องจากเป็นค่าเริ่มต้นของเรา มาเพิ่มตัวเริ่มต้นสำหรับการทดสอบ:<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>2.2.2.RELEASE</version>
<scope>test</scope>
</dependency>
ดังนั้นคลาสบริการ:
@Service
@RequiredArgsConstructor
public class RobotServiceImpl implements RobotService {
private final RobotDAO robotDAO;
@Override
public Robot update(Long id, Robot robot) {
Robot found = robotDAO.findById(id);
return robotDAO.update(Robot.builder()
.id(id)
.name(robot.getName() != null ? robot.getName() : found.getName())
.cpu(robot.getCpu() != null ? robot.getCpu() : found.getCpu())
.producer(robot.getProducer() != null ? robot.getProducer() : found.getProducer())
.build());
}
}
8 - ดึงวัตถุที่อัปเดตจากฐานข้อมูล 9-14 - สร้างวัตถุผ่านตัวสร้างหากวัตถุที่เข้ามามีฟิลด์ - ตั้งค่าถ้าไม่ใช่ - ปล่อยสิ่งที่อยู่ในฐานข้อมูล และดูการทดสอบของเรา:
@RunWith(MockitoJUnitRunner.class)
public class RobotServiceImplTest {
@Mock
private RobotDAO robotDAO;
private RobotServiceImpl robotService;
private static Robot testRobot;
@BeforeClass
public static void prepareTestData() {
testRobot = Robot
.builder()
.id(123L)
.name("testRobotMolly")
.cpu("Intel Core i7-9700K")
.producer("China")
.build();
}
@Before
public void init() {
robotService = new RobotServiceImpl(robotDAO);
}
1 — Runner 4 ของเรา — แยกบริการออกจากเลเยอร์ dao โดยการแทนที่การจำลอง 11 — ตั้งค่าเอนทิตีการทดสอบสำหรับคลาส (อันที่เราจะใช้เป็นหนูแฮมสเตอร์ทดสอบ) 22 — ตั้งค่าวัตถุบริการที่เราจะทดสอบ
@Test
public void updateTest() {
when(robotDAO.findById(any(Long.class))).thenReturn(testRobot);
when(robotDAO.update(any(Robot.class))).then(returnsFirstArg());
Robot robotForUpdate = Robot
.builder()
.name("Vally")
.cpu("AMD Ryzen 7 2700X")
.build();
Robot resultRobot = robotService.update(123L, robotForUpdate);
assertNotNull(resultRobot);
assertSame(resultRobot.getId(),testRobot.getId());
assertThat(resultRobot.getName()).isEqualTo(robotForUpdate.getName());
assertTrue(resultRobot.getCpu().equals(robotForUpdate.getCpu()));
assertEquals(resultRobot.getProducer(),testRobot.getProducer());
}
ที่นี่เราเห็นการแบ่งการทดสอบออกเป็นสามส่วนอย่างชัดเจน: 3-9 - การตั้งค่าการติดตั้ง 11 - การดำเนินการทดสอบส่วนที่ 13-17 - การตรวจสอบผลลัพธ์ รายละเอียดเพิ่มเติม: 3-4 - การตั้งค่าพฤติกรรมสำหรับโมก้าดาว 5 - การตั้งค่า อินสแตนซ์ที่เราจะอัปเดตเพิ่มเติมจากมาตรฐานของเรา 11 - ใช้วิธีการและรับอินสแตนซ์ผลลัพธ์ 13 - ตรวจสอบว่าไม่ใช่ศูนย์ 14 - ตรวจสอบรหัสผลลัพธ์และอาร์กิวเมนต์ของวิธีการที่ระบุ 15 - ตรวจสอบว่าชื่อได้รับการอัปเดตหรือไม่ 16 - ดูผลลัพธ์ด้วย cpu 17 - เนื่องจากเราไม่ได้ตั้งค่านี้ในฟิลด์อินสแตนซ์การอัปเดต จึงควรคงเหมือนเดิม มาตรวจสอบกัน 


GO TO FULL VERSION