นี่คือแนวทางของฉัน มีค่าใช้จ่ายในแง่ของเวลาเนื่องจากเป็นการทดสอบการปรับโครงสร้างใหม่ใน 4 ขั้นตอน
สิ่งที่ฉันจะเปิดเผยอาจจะประกอบได้ดีกว่าในองค์ประกอบที่มีความซับซ้อนมากกว่าสิ่งที่ปรากฏในตัวอย่างของคำถาม
อย่างไรก็ตามกลยุทธ์นั้นใช้ได้สำหรับผู้สมัครองค์ประกอบใด ๆ ที่จะทำให้เป็นมาตรฐานโดยอินเทอร์เฟซ (DAO, Services, Controllers, ... )
1. ส่วนต่อประสาน
ให้รวบรวมวิธีสาธารณะทั้งหมดจากMyDocumentServiceและให้รวมเข้าไว้ในอินเตอร์เฟส ตัวอย่างเช่น ถ้ามันไม่อยู่แล้วใช้ที่หนึ่งแทนการตั้งค่าใดคนหนึ่งใหม่
public interface DocumentService {
List<Document> getAllDocuments();
//more methods here...
}
จากนั้นเราบังคับให้MyDocumentServiceใช้อินเทอร์เฟซใหม่นี้
จนถึงตอนนี้ดีมาก ไม่มีการเปลี่ยนแปลงที่สำคัญเราเคารพสัญญาปัจจุบันและ behaivos ยังคงไม่ถูกแตะต้อง
public class MyDocumentService implements DocumentService {
@Override
public List<Document> getAllDocuments(){
//legacy code here as it is.
// with no changes ...
}
}
2. การทดสอบหน่วยของรหัสดั้งเดิม
ที่นี่เรามีงานหนัก เพื่อตั้งค่าชุดทดสอบ เราควรกำหนดหลาย ๆ กรณีให้มากที่สุด: กรณีที่ประสบความสำเร็จและกรณีข้อผิดพลาด สิ่งสุดท้ายคือสิ่งที่ดีต่อคุณภาพของผลลัพธ์
ตอนนี้แทนที่จะทดสอบMyDocumentServiceเราจะใช้ส่วนต่อประสานเป็นสัญญาที่จะทำการทดสอบ
ฉันจะไม่ลงรายละเอียดดังนั้นโปรดยกโทษให้ฉันหากรหัสของฉันดูง่ายเกินไปหรือไม่เชื่อเรื่องพระเจ้ามากเกินไป
public class DocumentServiceTestSuite {
@Mock
MyDependencyA mockDepA;
@Mock
MyDependencyB mockDepB;
//... More mocks
DocumentService service;
@Before
public void initService(){
service = MyDocumentService(mockDepA, mockDepB);
//this is purposed way to inject
//dependencies. Replace it with one you like more.
}
@Test
public void getAllDocumentsOK(){
// here I mock depA and depB
// wanted behaivors...
List<Document> result = service.getAllDocuments();
Assert.assertX(result);
Assert.assertY(result);
//... As many you think appropiate
}
}
ขั้นตอนนี้ใช้เวลานานกว่าขั้นตอนอื่นในแนวทางนี้ และมันสำคัญที่สุดเพราะมันจะกำหนดจุดอ้างอิงสำหรับการเปรียบเทียบในอนาคต
หมายเหตุ: เนื่องจากไม่มีการเปลี่ยนแปลงที่สำคัญเกิดขึ้นและ behaivor ยังคงไม่ถูกแตะต้อง ฉันแนะนำให้ทำแท็กที่นี่ใน SCM แท็กหรือสาขาไม่สำคัญ เพียงแค่ทำรุ่น
เราต้องการสำหรับการย้อนกลับการเปรียบเทียบรุ่นและอาจเป็นการประมวลผลแบบขนานของรหัสเก่าและรหัสใหม่
3. การปรับโครงสร้างใหม่
Refactor กำลังจะถูกนำไปใช้กับส่วนประกอบใหม่ เราจะไม่ทำการเปลี่ยนแปลงใด ๆ กับรหัสที่มีอยู่ ขั้นตอนแรกนั้นง่ายเหมือนการคัดลอกและวางMyDocumentServiceและเปลี่ยนชื่อเป็นCustomDocumentService (ตัวอย่าง)
คลาสใหม่ใช้DocumentServiceต่อไป จากนั้นไปปรับโครงสร้างgetAllDocuments ()อีกครั้ง (ให้เริ่มทีละหนึ่ง Pin-refactors)
อาจต้องมีการเปลี่ยนแปลงบางอย่างในส่วนต่อประสาน / วิธีการของ DAO ถ้าเป็นเช่นนั้นอย่าเปลี่ยนรหัสที่มีอยู่ ใช้วิธีการของคุณเองในส่วนต่อประสาน DAO เขียนคำอธิบายรหัสเก่าว่าเลิกแล้วและคุณจะรู้ในภายหลังว่าควรลบอะไร
เป็นสิ่งสำคัญที่จะไม่ทำลาย / เปลี่ยนแปลงการใช้งานที่มีอยู่ เราต้องการดำเนินการบริการทั้งสองแบบขนานและเปรียบเทียบผลลัพธ์
public class CustomDocumentService implements DocumentService {
@Override
public List<Document> getAllDocuments(){
//new code here ...
//due to im refactoring service
//I do the less changes possible on its dependencies (DAO).
//these changes will come later
//and they will have their own tests
}
}
4. การอัปเดต DocumentServiceTestSuite
ตกลงตอนนี้ส่วนที่ง่ายขึ้น เพื่อเพิ่มการทดสอบขององค์ประกอบใหม่
public class DocumentServiceTestSuite {
@Mock
MyDependencyA mockDepA;
@Mock
MyDependencyB mockDepB;
DocumentService service;
DocumentService customService;
@Before
public void initService(){
service = MyDocumentService(mockDepA, mockDepB);
customService = CustomDocumentService(mockDepA, mockDepB);
// this is purposed way to inject
//dependencies. Replace it with the one you like more
}
@Test
public void getAllDocumentsOK(){
// here I mock depA and depB
// wanted behaivors...
List<Document> oldResult = service.getAllDocuments();
Assert.assertX(oldResult);
Assert.assertY(oldResult);
//... As many you think appropiate
List<Document> newResult = customService.getAllDocuments();
Assert.assertX(newResult);
Assert.assertY(newResult);
//... The very same made to oldResult
//this is optional
Assert.assertEquals(oldResult,newResult);
}
}
ตอนนี้เรามีoldResult และ newResultทั้งสองได้รับการตรวจสอบอย่างอิสระ แต่เราสามารถเปรียบเทียบกันได้ การตรวจสอบครั้งสุดท้ายนี้เป็นทางเลือกและขึ้นอยู่กับผลลัพธ์ อาจจะไม่เทียบเท่า
อาจไม่ทำให้มีการเปรียบเทียบมากเกินไปในการเปรียบเทียบสองคอลเลกชันด้วยวิธีนี้ แต่จะใช้ได้กับวัตถุประเภทอื่น (pojos, เอนทิตีโมเดลข้อมูล, DTOs, Wrappers, ชนิดเนทีฟ ... )
หมายเหตุ
ฉันจะไม่กล้าบอกวิธีการทดสอบหน่วยหรือวิธีการใช้ libs จำลอง ฉันไม่กล้าที่จะไม่พูดว่าคุณต้องทำ refactor อย่างไร สิ่งที่ฉันอยากทำคือแนะนำกลยุทธ์ระดับโลก วิธีที่จะนำไปข้างหน้าขึ้นอยู่กับคุณ คุณรู้แน่ชัดว่าโค๊ดนั้นมีความซับซ้อนอย่างไรและหากกลยุทธ์ดังกล่าวน่าลอง ข้อเท็จจริงเช่นเวลาและทรัพยากรมีความสำคัญที่นี่ สิ่งสำคัญที่คุณคาดหวังจากการทดสอบเหล่านี้ในอนาคต
ฉันได้เริ่มตัวอย่างของฉันโดยบริการและฉันจะตามด้วย DAO เป็นต้น จะลึกเข้าไปในระดับการพึ่งพา มากหรือน้อยก็สามารถอธิบายได้ว่าเป็นกลยุทธ์ขึ้นด้านล่าง อย่างไรก็ตามสำหรับการเปลี่ยนแปลงเล็กน้อย / การรีแฟคเตอร์ ( เช่นตัวอย่างที่แสดงในตัวอย่างของทัวร์ ) ด้านล่างจะทำให้ทำงานง่ายขึ้น เนื่องจากขอบเขตของการเปลี่ยนแปลงมีน้อย
ในที่สุดมันก็ขึ้นอยู่กับคุณที่จะลบรหัสที่เลิกใช้แล้วและเปลี่ยนเส้นทางการอ้างอิงเก่าไปยังรหัสใหม่
ลบการทดสอบที่เลิกใช้แล้วและงานเสร็จแล้ว หากคุณทำเวอร์ชันโซลูชันเก่าด้วยการทดสอบคุณสามารถตรวจสอบและเปรียบเทียบกันได้ตลอดเวลา
ผลที่ตามมาจากการทำงานจำนวนมากคุณมีการทดสอบรหัสดั้งเดิมตรวจสอบและรุ่น และรหัสใหม่ทดสอบตรวจสอบและพร้อมที่จะเป็นเวอร์ชั่น