上一篇提到6種較不易進行測試的情況。接下來就來細說為何難測的原因及重構方法。
第一種情況:
程式無聲無息的做完了,沒有提供任可訊息可供判斷!
這種情形,就好像太空船進到黑洞,完全無法回傳任何訊息一樣。無法取得訊息,就很難進行測試。當然還是能由一些間接方法來推測,但這樣做很容易因環境變更,而使得Unit Test 失敗。最好的方法還是程式能夠提供適當的訊息供Unit Test 做判斷。
假設有一支 ReportAgent,它可產生 Excel 和 PDF 報表。程式碼如下:
public class ReportAgent {
//產生房客 Excel 報表資料
public boolean createExcelReport(Tenant tenant) throws IOException {
if (tenant != null) {
HSSFWorkbook wb = new HSSFWorkbook();
HSSFSheet sheet = wb.createSheet();
HSSFRow row = sheet.createRow(0);
row.createCell(0).setCellValue(tenant.getName());
row.createCell(1).setCellValue(tenant.getAge());
row.createCell(2).setCellValue(tenant.getCareer());
FileOutputStream out = new FileOutputStream("report.xls");
wb.write(out);
out.close();
return true;
} else {
return false;
}
}
//產生房客 PDF 報表資料
public boolean createPdfReport(Tenant tenant) throws FileNotFoundException,
DocumentException {
if (tenant != null) {
Document document = new Document();
PdfWriter.getInstance(document, new FileOutputStream("report.pdf"));
document.open();
document.add(new Paragraph("Name:"+tenant.getName()));
document.add(new Paragraph("Age:"+tenant.getAge()));
document.add(new Paragraph("Career:"+tenant.getCareer()));
document.close();
return true;
} else {
return false;
}
}
//產生房客 Word 報表資料
public boolean crateWordReport(Tenant tenant) throws IOException{
//TODO
return true;
}
}
使用者需經由RentServiceImpl 才能產生房客報表。報表型態(ReportType)有三種,分別為Excel、PDF、WORD。但是房客報表只提供EXCEL和PDF二種報表的選擇,並不提供WORD報表。程式碼如下
public enum ReportType {
EXCEL,PDF,WORD
}
public class RentServiceImpl implements RentService {
private ReportAgent reportAgent;
public void setReportAgent(ReportAgent reportAgent) {
this.reportAgent = reportAgent;
}
@Override
public void createReport(Tenant tenant, ReportType type)
throws IOException, DocumentException {
if (type == ReportType.EXCEL) {
reportAgent.createExcelReport(tenant);
} else if (type == ReportType.PDF) {
reportAgent.createPdfReport(tenant);
}
}
}
當對 RentServiceImpl 中的createReport()進行測試時,無法得知是否執行正確。例如:當傳入的ReportType 為PDF 時,是否真的產生PDF報表,如果傳入的ReportType 為WORD,程式也不會有任何反應,所以這個測試只要不出Exception,所有的條件都會過,那這就不是一個有效的測試。測試碼如下
public class RentServiceTest {
private RentServiceImpl service;
@Before
public void setUp(){
service=new RentServiceImpl();
service.setReportAgent(new ReportAgent());
}
//無效的測試,無法判別錯誤
@Test
public void testCreateReport() throws IOException, DocumentException{
service.createReport(getTenant(), ReportType.PDF);
service.createReport(getTenant(), ReportType.WORD);
}
private Tenant getTenant() {
Tenant tenant=new Tenant(Identity.GENERAL);
tenant.setName("Jim");
tenant.setAge(30);
tenant.setCareer("Doctor");
return tenant;
}
}
接下來,要來重構createReport(),當某個型態的report有被順利產出時,就回傳這個型號代號,若沒有這個型態的report就丟Exception。程式碼如下:
public ReportType createReport(Tenant tenant, ReportType type)
throws IOException, DocumentException, ReportException {
if (type == ReportType.EXCEL) {
reportAgent.createExcelReport(tenant);
return ReportType.EXCEL;
} else if (type == ReportType.PDF) {
reportAgent.createPdfReport(tenant);
return ReportType.PDF;
}else {
throw new ReportException("Format Not Support");
}
}
@Test
public void testCreateReport() throws IOException, DocumentException, ReportException{
ReportType reportType=service.createReport(getTenant(), ReportType.PDF);
Assert.assertEquals(ReportType.PDF, reportType);
try {
service.createReport(getTenant(), ReportType.WORD);
Assert.fail();
} catch (Exception e) {
Assert.assertTrue(true);
}
}
這樣,測試程式可依回傳值來判斷是否有產生正確的Report。如果有傳入錯誤型態,程式也會以Exception 的方式告知。有了這些訊息,測試程式就能驗證邏輯是否正確。
沒有留言:
張貼留言