2015-10-02 49 views
0

我目前正在使用以下方法和單元測試的方法。我認爲測試可以/應該被分解成更多的測試,但我不確定有多少測試要寫出來,或者更重要的部分是什麼,尤其是考慮到該方法使用sql查詢等來建立Connection。 。所有幫助表示讚賞。JAVA最佳實踐單元測試與JUnit

Java方法:

public static ArrayList<HashMap<String, String>> executeSelect(
     Connection conn, Statement stmt, Query query) { 

    ResultSet rs = null; 
    ArrayList<HashMap<String, String>> serviceRequests = new ArrayList<HashMap<String, String>>(); 

    try { 
     long queryStart = System.nanoTime(); 
     rs = stmt.executeQuery(query.getQuery()); 
     long queryEnd = System.nanoTime(); 
     long queryDuration = queryEnd-queryStart; 
     queryTime = String.valueOf(queryDuration); 

     while (rs.next()) { 

      HashMap<String, String> serviceRequestData = new HashMap<>(); 

      if (QueryUtil.hasColumn(rs, "ID")) { 
       String id = rs.getString("ID"); 
       serviceRequestData.put("ID", id); 
      } 
      else{ 
       serviceRequestData.put("ID", " "); 
      } 
      if (QueryUtil.hasColumn(rs, "FN_Contact")) { 
       String firstName = rs.getString("FN_Contact"); 
       serviceRequestData.put("FN_Contact", firstName); 
      } 
      else{ 
       serviceRequestData.put("FN_Contact", " "); 
      } 
      if (QueryUtil.hasColumn(rs, "LN_Contact")) { 
       String lastName = rs.getString("LN_Contact"); 
       serviceRequestData.put("LN_Contact", lastName); 
      } 
      else{ 
       serviceRequestData.put("LN_Contact", " "); 
      } 
      if (QueryUtil.hasColumn(rs, "Notes")) { 
       String notes = rs.getString("Notes"); 
       serviceRequestData.put("Notes", notes); 
      } 
      else{ 
       serviceRequestData.put("Notes", " "); 
      } 
      if (QueryUtil.hasColumn(rs, "Email")) { 
       String email = rs.getString("Email"); 
       serviceRequestData.put("Email", email); 
      } 
      else{ 
       serviceRequestData.put("Email", " "); 

      } 

      serviceRequests.add(serviceRequestData); 

     } 
    } catch (SQLException e) { 
     e.printStackTrace(); 
     sqlException = true; 
    } 
    return serviceRequests; 
} 

JUnit測試:

@Test 
public void testFirstName() { 
    ArrayList<HashMap<String, String>> testMap = new ArrayList<HashMap<String,String>>(); 
    Connection conn = null; 
    Statement stmt = null; 
    try { 
     Class.forName("com.mysql.jdbc.Driver"); 

     String connectionUrl = "jdbc:mysql://localhost:3306/gc_image"; 
     String connectionUser = "root"; 
     String connectionPassword = "GCImage"; 
     conn = DriverManager.getConnection(connectionUrl, connectionUser, 
       connectionPassword); 
     conn. 
     stmt = conn.createStatement(); 
     Query testQuery = new Query(); 
     testQuery 
       .setQuery("select * from service_request where FN_contact = 'Trevor'"); 
     testMap = QueryController.executeSelect(conn, stmt, testQuery); 

     assertEquals("Janke", testMap.get(0).get("LN_Contact")); 
     assertEquals("Hello World", testMap.get(0).get("Notes")); 
     assertEquals("[email protected]", testMap.get(0).get("Email")); 
     assertEquals("ID", testMap.get(0).get("7")); 

    } catch (ClassNotFoundException e) { 
     e.printStackTrace(); 
    } catch (SQLException e) { 
     e.printStackTrace(); 
    } finally { 
     try { 
      stmt.close(); 
      conn.close(); 
     } catch (SQLException e) { 
      e.printStackTrace(); 
     } 
    } 

} 

回答

3

你應該確定一下這個測試的設置的一部分是不是測試方法的真正部分開始;即什麼是可以提取到@Before@After方法的樣板文件。這可能需要您將幾個局部變量拉入類變量中。這使每個@Test方法都不那麼冗長,並允許您專注於測試下的功能。

接下來您應該刪除所有catch塊,或者如果您的代碼或測試代碼引發了意外異常,則應通過類似fail(exception.getMessage())的測試來通過測試。如果刪除它們,很容易將單元測試的方法簽名更改爲throws Exception,以便在引發異常時使其一般性失敗。現在,您可能完全無法連接到您的設置中的數據庫,並且Junit測試仍將變爲綠色!

理想情況下,您可以進行單元測試,涵蓋每個if...else塊。那會給你10個測試。其中,重點(Assert)將確認serviceRequests中找到/未找到的值的存在。你也應該測試你的異常處理,所以你需要一個強制SQLException被捕獲的測試。

我最終會建議,爲了減少開銷,您可以考慮使用模擬框架,比如Mockito來完全清除數據庫I/O。這個SO question有一些嘲笑數據庫的好例子。

executeSelect()注意到幾個簡單的事情,可能是固定的:

  • 取出Connection參數 - 這是不使用的,因爲Statement已經被實例化。
  • 考慮拋出SQLException而不是返回一個List - 它給出了一個錯誤的廣告,即DB讀取已成功執行。
  • 優先考慮具體類上的接口和抽象類:將您的方法簽名和serviceRequestsArrayList<HashMap<String, String>>更改爲List<Map<String, String>>。在許多資源中,Josh Bloch的Effective Java是這個主題的很好的參考。

您可以簡化這種方法甚至更多 - 這會使得測試更加簡單 - 通過下面的代碼移動到另一個方法:

long queryStart = System.nanoTime(); 
    rs = stmt.executeQuery(query.getQuery()); 
    long queryEnd = System.nanoTime(); 
    long queryDuration = queryEnd-queryStart; 
    queryTime = String.valueOf(queryDuration); 

,然後只ResultSet突入executeSelect() ...或任何它將被重命名爲:)。

+0

非常豐富和全面的答案。謝謝 – GregH

+0

不客氣。我想「TL; DR」總是努力將盡可能少的代碼放入測試方法中。越少,意圖就越清晰,並且更好地相信所要測試的是實際上正在測試的東西:) – Keith

+0

你是什麼意思做'失敗(e.getMessage))'? 'fail()'不在JUnit庫中?這個函數應該包含什麼? – GregH