上一篇提到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 的方式告知。有了這些訊息,測試程式就能驗證邏輯是否正確。
沒有留言:
張貼留言