ปัญหาในการใช้ฐานข้อมูล 'ของจริง' สำหรับการทดสอบหน่วยคือการตั้งค่าการถอดและการแยกการทดสอบ คุณไม่ต้องการหมุนฐานข้อมูล MySQL ใหม่ทั้งหมดและสร้างตารางและข้อมูลเพียงแค่การทดสอบหน่วยเดียว ปัญหานี้เกี่ยวข้องกับลักษณะภายนอกของฐานข้อมูลและฐานข้อมูลการทดสอบของคุณไม่ทำงานการทดสอบหน่วยของคุณล้มเหลว นอกจากนี้ยังมีปัญหาในการทำให้แน่ใจว่าคุณมีฐานข้อมูลเฉพาะสำหรับการทดสอบ พวกเขาสามารถเอาชนะได้ แต่มีคำตอบที่ง่ายกว่า
การเยาะเย้ยฐานข้อมูลเป็นหนึ่งตัวเลือกแต่จะไม่ทดสอบการสืบค้นจริงที่เรียกใช้ มันสามารถใช้เป็นวิธีที่ง่ายกว่ามากเมื่อคุณต้องการตรวจสอบให้แน่ใจว่าข้อมูลจาก DAO ผ่านระบบอย่างถูกต้อง แต่สำหรับการทดสอบ DAO เองคุณต้องการบางสิ่งบางอย่างที่อยู่เบื้องหลัง DAO มีข้อมูลและแบบสอบถามทำงานอย่างถูกต้อง
สิ่งแรกที่ต้องทำคือใช้ฐานข้อมูลในหน่วยความจำ HyperSQLเป็นตัวเลือกที่ยอดเยี่ยมสำหรับสิ่งนี้เพราะมันมีความสามารถในการเลียนแบบภาษาของฐานข้อมูลอื่น - เพื่อให้ความแตกต่างเล็กน้อยระหว่างฐานข้อมูลยังคงเหมือนเดิม (ชนิดข้อมูล, ฟังก์ชั่นและอื่น ๆ ) hsqldb ยังมีคุณสมบัติที่ดีสำหรับการทดสอบหน่วยอีกด้วย
db.url=jdbc:hsqldb:file:src/test/resources/testData;shutdown=true;
สิ่งนี้จะโหลดสถานะของฐานข้อมูล (ตารางข้อมูลเริ่มต้น) จากtestData
ไฟล์ shutdown=true
จะปิดฐานข้อมูลโดยอัตโนมัติเมื่อการเชื่อมต่อล่าสุดปิดลง
ใช้การฉีดแบบพึ่งพาให้หน่วยทดสอบเลือกฐานข้อมูลที่แตกต่างจากที่ใช้ในการสร้าง (หรือการทดสอบหรือท้องถิ่น)
DAO ของคุณจะใช้ฐานข้อมูลแบบฉีดซึ่งคุณสามารถเปิดการทดสอบกับฐานข้อมูล
การทดสอบหน่วยจะมีลักษณะเหมือน (พวงของสิ่งที่น่าเบื่อไม่รวมถึงความกะทัดรัด):
@Before
public void setUpDB() {
DBConnection connection = new DBConnection();
try {
conn = connection.getDBConnection();
insert = conn.prepareStatement("INSERT INTO data (txt, ts, active) VALUES (?, ?, ?)");
} catch (SQLException e) {
e.printStackTrace();
fail("Error instantiating database table: " + e.getMessage());
}
}
@After
public void tearDown() {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
private void addData(String txt, Timestamp ts, boolean active) throws Exception {
insert.setString(1, txt);
insert.setTimestamp(2, ts);
insert.setBoolean(3, active);
insert.execute();
}
@Test
public void testGetData() throws Exception {
// load data
Calendar time = Calendar.getInstance();
long now = time.getTimeInMillis();
long then1h = now - (60 * 60 * 1000); // one hour ago
long then2m = now - (60 * 1000 * 2); // two minutes ago
addData("active_foo", new Timestamp(then1h), true); // active but old
addData("inactive_bar", new Timestamp(then1h), false); // inactive and old
addData("active_quz", new Timestamp(then2m), true); // active and new
addData("inactive_baz", new Timestamp(then2m), false); // inactive and new
DataAccess dao = new DataAccess();
int count = 0;
for (Data data : dao.getData()) {
count++;
assertTrue(data.getTxt().startsWith("active"));
}
assertEquals("got back " + count + " rows instead of 1", count, 1);
}
ดังนั้นคุณจะได้รับการทดสอบหน่วยที่เรียก DAO และใช้ข้อมูลที่ตั้งค่าในฐานข้อมูลการบินที่มีอยู่ในช่วงระยะเวลาของการทดสอบ คุณไม่ต้องกังวลเกี่ยวกับทรัพยากรภายนอกหรือสถานะของฐานข้อมูลก่อนการรันหรือการกู้คืนสู่สถานะที่รู้จัก (เช่นกัน 'สถานะที่รู้จัก' คือ 'ไม่มีอยู่' ซึ่งเป็นสิ่งสำคัญที่จะเปลี่ยนกลับ)
DBUnitสามารถทำสิ่งที่ฉันอธิบายกระบวนการที่ง่ายกว่าในการตั้งค่าฐานข้อมูลการสร้างตารางและโหลดข้อมูล หากคุณต้องการใช้ฐานข้อมูลจริงด้วยเหตุผลบางอย่างนี่เป็นเครื่องมือที่ใช้งานได้ดีกว่า
รหัสข้างต้นเป็นส่วนหนึ่งของโครงการ Maven ที่ฉันเขียนเพื่อพิสูจน์แนวคิดTestWithHsqldb บน github