2013-04-05 14 views
0

我開發利用與UP Design.In這種精化迭代一個下載管理器,我的主要用例:下載file.Here是Download.java如何爲下載管理器編寫測試驅動的java類?

public class Download implements Runnable { 

// Max size of download buffer. 
private static final int MAX_BUFFER_SIZE = 1024; 

// These are the status names. 
public static final String STATUSES[] = {"Downloading", "Complete"}; 

// These are the status codes. 
public static final int DOWNLOADING = 0; 
public static final int COMPLETE = 1; 
public static void main(String[] args) throws MalformedURLException { 
    System.out.println("Welcome to Download Manager."); 
    System.out.println("Enter a URL."); 
    URL url; 
    String s; 
    Scanner scan= new Scanner(System.in); 
    s=scan.nextLine(); 
    url= new URL(s); 
    Download download=new Download(url); 

} 

private URL url; // download URL 
private int size; // size of download in bytes 
private int downloaded; // number of bytes downloaded 
private int status; // current status of download 

// Constructor for Download. 
public Download(URL url) { 
    this.url = url; 
    size = -1; 
    downloaded = 0; 
    status = DOWNLOADING; 

    // Begin the download. 
    download(); 
} 
// Start or resume downloading. 
private void download() { 
    System.out.println("Starting."); 
    Thread thread = new Thread(this); 
    thread.start(); 
} 
// Download file. 
public void run() { 
    RandomAccessFile file = null; 
    InputStream stream = null; 

    try { 
     // Open connection to URL. 
     HttpURLConnection connection = 
       (HttpURLConnection) url.openConnection(); 

     // Specify what portion of file to download. 
     connection.setRequestProperty("Range", 
       "bytes=" + downloaded + "-"); 

     // Connect to server. 
     connection.connect(); 


     int contentLength = connection.getContentLength(); 


    /* Set the size for this download if it 
    hasn't been already set. */ 
     if (size == -1) { 
      size = contentLength; 

     } 

     // Open file and seek to the end of it. 
     file = new RandomAccessFile(getFileName(url), "rw"); 
     file.seek(downloaded); 

     stream = connection.getInputStream(); 
     while (status == DOWNLOADING) { 
    /* Size buffer according to how much of the 
     file is left to download. */ 
      byte buffer[]; 
      if (size - downloaded > MAX_BUFFER_SIZE) { 
       buffer = new byte[MAX_BUFFER_SIZE]; 
      } else { 
       buffer = new byte[size - downloaded]; 
      } 
      System.out.print("%"+(downloaded/size)+'\r'); 
      // Read from server into buffer. 
      int read = stream.read(buffer); 
      if (read == -1){ 
       System.out.println("File was downloaded"); 
       break; 
      } 

      // Write buffer to file. 
      file.write(buffer, 0, read); 
      downloaded += read; 

     } 

    /* Change status to complete if this point was 
    reached because downloading has finished. */ 
     if (status == DOWNLOADING) { 
      status = COMPLETE; 

     } 
    } catch (Exception e) { 
     System.out.println("Error!"); 
    } finally { 
     // Close file. 
     if (file != null) { 
      try { 
       file.close(); 
      } catch (Exception e) {} 
     } 

     // Close connection to server. 
     if (stream != null) { 
      try { 
       stream.close(); 
      } catch (Exception e) {} 
     } 
    } 
} 

我怎麼可以這樣寫代碼的測試代碼?例如,我應該測試URL驗證,還是應該控制文件是否正在下載?我該如何做這些測試? 謝謝。

+0

你的代碼是非常糟糕的測試。您應該研究依賴注入和嘲笑,然後將其分成多個,更容易測試對象。 – millimoose 2013-04-05 23:20:35

+0

@millimoose我如何看待依賴注入和嘲笑? – ntf 2013-04-06 08:18:56

+0

@millimoose我是TDD的新手,我無法找到如何拆分它。 – ntf 2013-04-06 08:20:01

回答

0

回答你的直接問題:寫一個測試這些代碼真的很難。

單元測試的美妙之處在於它們向您展示了您的代碼的客戶端可以如何輕鬆地使用該模塊。有一個叫「面向對象的分析和設計」的大領域,旨在幫助程序員解決這些問題。

在這裏,你應該改變你的代碼,以便存在幾個單一職責的例程,例如,一個用於通過網絡進行通信,一個用於將自定義數據流存儲到HDD,另一個用於處理使用輸入。通過這種方式,您可以單獨測試這些「例程」,甚至可以提供您自己的「網絡」環境(例如將硬編碼值替換爲真正連接到網絡的類)

+0

感謝您的回覆,但是我仍然無法找到如何爲此類編寫tes類。例如,我查看了一些示例,其中使用了assertEqual()。如何在我的情況下使用assertEqual。任何想法? – ntf 2013-04-06 08:18:11

1

您編寫的類很難測試,它試圖做太多。如果您要將某些職責提取到外部依賴項中,則最終可能只有一個類來管理從URL中進行的低級別下載,而另一個類可以管理本地文件系統。例如:

interface UrlDownloader { 
    InputStream download(URL url, int offset) throws IOException; 
} 

interface DownloadFolder { 
    List<String> getFiles(); 
    void writeToFile(String filename, InputStream contents) throws IOException; 
    void getFileSize(String filename); 
} 

然後可以使用這些類的模擬版本對下載管理器進行測試。有了這樣一個的Mockito庫,你可以寫這樣一個測試:

@Test 
public void canDownloadCompleteFile() throws IOException { 
    URL url = new URL("http://example.com/file.txt"); 
    InputStream inputStream = new ByteArrayInputStream("abc".getBytes()); 
    UrlDownloader urlDownloader = mock(UrlDownloader.class); 
    DownloadFolder downloadFolder = mock(DownloadFolder.class); 
    when(urlDownloader.download(url, 0)).thenReturn(inputStream); 

    DownloadManager manager = new DownloadManager(urlDownloader, downloadFolder); 

    manager.download(url); 

    verify(downloadFolder).writeToFile("file.txt", inputStream); 
} 

與依賴時拋出異常,你的Mockito可以控制的,或驗證方法被調用特定的參數。

另一種方法是創建實現接口的假類,並使用內存中的數據結構而不是真正的文件系統/網絡。這些類的狀態然後可以用的assertEquals等測試:

@Test 
public void canDownloadCompleteFile() throws IOException { 
    URL url = new URL("http://example.com/file.txt"); 
    FakeDownloadFolder downloadFolder = new FakeDownloadFolder(); 
    FakeUrlDownloader urlDownloader = new FakeUrlDownloader(); 
    urlDownloader.setUrlContents(url, "abc".getBytes()); 

    DownloadManager manager = new DownloadManager(urlDownloader, downloadFolder); 

    manager.download(url); 

    assertEquals("abc".getBytes(), downloadFolder.getFileAsByteArray("file.txt")); 
} 

背後的測試驅動開發的想法是,你只寫由測試支持代碼。所以你需要實現足夠的DownloadManager來傳遞第一個測試,然後添加另一個測試(例如,恢復未完成的下載)。

相關問題