2011-09-27 125 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

相关问题