2013-07-16 374 views
6

我有一個類如下:用JMockit模擬私人靜態字段?

class ClassA { 
    private static File myDir; 

    // myDir is created at some stage 

    private static String findFile(final String fileName) { 
     for (final String actualBackupFileName : myDir.list()) { 
      if (actualBackupFileName.startsWith(removeExtensionFrom(backupFile))) { 
       return actualBackupFileName; 
      } 
     } 
    } 
} 

所以,基本上,我想嘲弄了File類,這樣,當列表()調用它,它返回我在我的測試類中定義字符串列表來測試這個類。

我得到了以下內容,但它在一分鐘內沒有工作,可能有一些明顯的我做錯了 - 我是JMockit的新手 - 非常感謝任何幫助!

@Mocked("list") File myDir; 

@Test 
    public void testClassA() { 
    final String[] files = {"file1-bla.txt"}; 

    new NonStrictExpectations() {{ 
     new File(anyString).list(); 
     returns(files); 
    }}; 

    String returnedFileName = Deencapsulation.invoke(ClassA.class, "findFile","file1.txt"); 

    // assert returnedFileName is equal to "file1-bla.txt" 
    } 

當運行上述測試我得到的ClassA中的MYDIR場一個NullPointerException - 所以它看起來像它沒有得到正確的嘲笑?

回答

10

JMockit(或任何其他嘲諷工具)不模擬字段或變量,它嘲笑類型(類,接口等),如果這些類型的情況下,獲得存儲在被測代碼內部並不相關。

ClassA實施例試驗:

@Test 
public void testClassA(@Mocked File myDir) 
{ 
    new Expectations() {{ myDir.list(); result = "file1-bla.txt"; }}; 

    String returnedFileName = new ClassA().publicMethodThatCallsFindFile("file1.txt"); 

    assertEquals("file1-bla.txt", returnedFileName); 
} 

上面應該工作。請注意,直接測試private方法(或訪問private字段)被認爲是不好的做法,所以我在這裏避免了它。此外,最好避免嘲笑File課程。相反,只測試您的public方法,並使用實際文件而不是模擬文件系統。

+0

非常好,非常感謝你的幫助Rogerio,這對你的代碼有一個小的改變 - @Mocked File myDir必須改爲@Mocked(methods = {「list」})文件myDir讓它工作。我想這可能是因爲Deencapsualtion.invoke調用在某個時候可能需要一個真正的File對象,並且嘲笑所有的方法似乎會干擾某些事情。我是一個新用戶,所以不能投票給你 - 否則我會! – user2586917

+1

太棒了!嘲笑'文件'確實會導致意外的失敗,至少在舊版本的JMockit中。我隨你的修改編輯了答案。 –

+0

@Rogério,上面創建一個模擬對象('myDir')的方式導致引用爲null,導致'myDir.list()'失敗並帶有'NPE'。任何想法爲什麼? – mystarrocks

0

試試這個:

new Expectations {{ 
    invoke(File.class, "list", null, null); 
    returns(files); 
}} 
+1

謝謝,但文檔說invoke是調用一個靜態方法 - 列表()上的文件不是靜態的 - 似乎沒有工作。 – user2586917

7

您可以使用Deencapsulation類中的setField方法。注意下面的例子:

Deencapsulation.setField(ClassA, "File", your_desired_value);