2011-09-27 170 views
0

在已經花了很多時間在這個測試並不能對我這樣推理出來的,我沒有別的選擇,而不是找你幫忙:)JMockit異常塊上的NullPointerException?

使用JMockit測試一些我自己的JDBC「包裝」的上課,我走到了死衚衕。

這是類IM測試:

public class JdbcConnectionProperties { 
    private Properties properties = new Properties(); 
    private String username; 
    private String password; 
    private String connectionString; 

    public JdbcConnectionProperties(String propertiesFilePath) { 
     loadProperties(propertiesFilePath); 
    } 

    public void setProperties() { 
     username = properties.getProperty("user"); 
     password = properties.getProperty("password"); 

     String connectionType = properties.getProperty("connection_type"); 
     String serverAddress = properties.getProperty("server_address"); 
     String port = properties.getProperty("port"); 
     String sid = properties.getProperty("sid"); 

     //Create a connection string 
     connectionString = "jdbc:oracle:" + connectionType + ":@" + serverAddress + ":" + port + ":" + sid; 
    } 


    private void loadProperties(String propertiesFilePath) { 
     String filePath = Thread.currentThread().getContextClassLoader().getResource(propertiesFilePath).getFile(); 
     //Load properties from classpath 
     try { 
      properties.load(new FileInputStream(filePath)); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    } 

    public String getUsername() { 
     return username; 
    } 

    public String getPassword() { 
     return password; 
    } 

    public String getConnectionString() { 
     return connectionString; 
    } 

    public Properties getProperties() { 
     return properties; 
    } 
} 

這是測試:

public class JdbcConnectionPropertiesTest { 

    @Test 
    public void testSetProperties(
//   @Mocked final Properties properties 
    ) throws Exception { 

     //Mock loadFilePath method so i dont end up mocking a ton of classes 
     new MockUp<JdbcConnectionProperties>() { 
      @Mock 
      void loadProperties(String propertiesFilePath) { 
       //Doing nothing, simple "stub" method 
      } 
     }; 

     JdbcConnectionProperties jdbcConnectionProperties = new JdbcConnectionProperties("bla"); 
//  Deencapsulation.setField(jdbcConnectionProperties, "properties", properties); 
//  Mockit.stubOutClass(JdbcConnectionProperties.class, "loadProperties"); 
     final String username = "username"; 
     final String password = "password"; 
     final String connectionType = "thin"; 
     final String serverAddress = "localhost"; 
     final String port = "1521"; 
     final String sid = "orcl"; 
     String connectionString = "jdbc:oracle:" + connectionType + ":@" + serverAddress + ":" + port + ":" + sid; 

     new Expectations() { 
      @Mocked 
      Properties properties; 

      { 
       properties.get("user"); 
       result = username; 

       properties.get("password"); 
       result = password; 

       properties.get("connection_type"); 
       result = connectionType; 

       properties.get("server_address"); 
       result = serverAddress; 

       properties.get("port"); 
       result = port; 

       properties.get("sid"); 
       result = sid; 
      } 
     }; 

     jdbcConnectionProperties.setProperties(); 

     Assert.assertEquals("Incorrect user", username, jdbcConnectionProperties.getUsername()); 
     Assert.assertEquals("Incorrect password", password, jdbcConnectionProperties.getPassword()); 
     Assert.assertEquals("Incorrect connection string", connectionString, jdbcConnectionProperties.getConnectionString()); 
    } 
} 

有兩點要注意。我嘗試用Deencapsulation將嘲諷的屬性隱藏到對象中(我讓他們在代碼中註釋)。

我試着用@Mocked註釋來嘲笑它。

我試着用stubOutClass存根。

這不是我正在寫的第一個測試,但是我相對比較新的JMockit。 我之前寫的測試從來沒有讓我像這樣的頭痛。我想我用JMockit寫了大約20-30個測試,從來沒有像這樣的問題。

錯誤的是(在所有提到的情況):

java.lang.NullPointerException 
    at java.util.Hashtable.get(Hashtable.java:335) 
    at jdbc.JdbcConnectionPropertiesTest$2.<init>(JdbcConnectionPropertiesTest.java:49) 
    at jdbc.JdbcConnectionPropertiesTest.testSetProperties(JdbcConnectionPropertiesTest.java:44) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:71) 
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:199) 
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:62) 
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120) 

類是非常簡單的。測試應該非常簡單。但不知何故測試會在Expectations塊上崩潰(在第一個屬性期望值上)。如果我評論第一個,那麼它會繼續把它放在下一個。嘗試任何,anyString參數匹配。

我看到它的方式,我嘲笑JdbcConnectionProperties loadProperties,所以我可以簡化我的測試。然後我將一個模擬的Properties對象傳遞給測試。

然後...

...它應該工作。順便說一句,我從來沒有在異常塊中看到這個數量級的異常。

謝謝。

回答

2

Hashtable#get是JMockit默認情況下不會嘲笑的幾種方法之一,因爲它可能會干擾JDK或模擬時與JMockit本身。你可以通過明確地要求這個特定的測試進行模擬,使用@Mocked("get")

在測試中使用實際的「.properties」文件可能會更簡單,但沒有模擬。

+0

你能解釋一下爲什麼嗎?因爲它的同步(線程安全)?有沒有可能導致此類問題的方法列表?我提供的解決方案非常簡單且正確,但如果您有資源討論提及的行爲,這將有助於未來。謝謝。 – pfh

+0

有一個列表,但它在代碼中(參見'ExpectationsModifier'類)。原因在於,當JMockit嘲笑一個類時,它臨時重新定義它在JVM中的字節碼,影響所有實例和所有方法調用,而不管它們來自何處(實際上,在類加載期間過濾調用)。將來,這些類型的問題將通過對被測試(調用者)代碼進行字節碼修改而不是模擬代碼來消除;但是我需要一段時間來實現它。 –

0
new Expectations() { 
      @Mocked("getProperty") 
      Properties properties; 

      { 
       properties.getProperty("user"); 
       result = username; 

       properties.getProperty("password"); 
       result = password; 

       properties.getProperty("connection_type"); 
       result = connectionType; 

       properties.getProperty("server_address"); 
       result = serverAddress; 

       properties.getProperty("port"); 
       result = port; 

       properties.getProperty("sid"); 
       result = sid; 
      } 
     }; 

謝謝羅傑里奧。正如他指出的那樣,原因是「內部」階層嘲笑。記住一個非常小的限制。

需要注意一些其他類(我希望我能寫):

Classes to have in mind while mocking with JMockit