2009-09-26 59 views
7

我在寫一個類似TotalCommander的應用程序。我有一個單獨的文件列表組件和一個模型。型號支持的聽衆和問題,在下面的方式像CurrentDirChanged等事件的通知:單元測試一個Swing組件

 
private void fireCurrentDirectoryChanged(final IFile dir) { 
    if (SwingUtilities.isEventDispatchThread()) 
     for (FileTableEventsListener listener : tableListeners) 
      listener.currentDirectoryChanged(dir); 
    else { 
     SwingUtilities.invokeLater(new Runnable() { 
      public void run() { 
       for (FileTableEventsListener listener : tableListeners) 
        listener.currentDirectoryChanged(dir); 
      } 
     }); 
    } 
} 

我寫了一個簡單的測試此:

 
@Test 
public void testEvents() throws IOException { 
    IFile testDir = mockDirectoryStructure(); 
    final FileSystemEventsListener listener = 
       context.mock(FileSystemEventsListener.class); 
    context.checking(new Expectations() {{ 
     oneOf(listener).currentDirectoryChanged(with(any(IFile.class))); 
    }}); 

    FileTableModel model = new FileTableModel(testDir); 
    model.switchToInnerDirectory(1); 
} 

這是不行的,因爲沒有EventDispatchThread。有沒有任何方法可以在無頭構建中進行單元測試?

單元測試的Java Swing JMock的

回答

10

注意,在UI的東西一般來說單元測試是很困難的,因爲你必須模擬出了很多的東西,這僅僅是不可用的。
因此,開發應用程序(任何類型)時的主要目標總是儘可能地將UI主體與主應用程序邏輯分開。在這裏有很強的依賴性,使得單元測試真的很難,基本上是一場噩夢。通常通過使用諸如MVC類型的方法來利用這種方式,其中您主要測試您的控制器類,並且您的視圖類除了構建UI並將其操作和事件委託給控制器之外沒有任何作用。這將職責分開並使測試更容易。

此外,你不應該測試已經由框架提供的東西,比如測試事件是否被正確觸發。你應該測試你自己寫的邏輯。

+1

我寫了這篇文章,並且我想測試它在應該使用正確的參數時觸發事件。我猜,我在這裏做錯了什麼,是確保模型中的GUI線程。模型不是Swing組件,它不必在GUI線程內觸發事件。我在這裏想的是對的嗎? – 2009-09-26 10:34:24

12

this

巨星是庫的集合,下Apache 2.0 license發佈的,其使命是簡化軟件測試。它是由各種模塊,可與TestNGJUnit使用的...

+0

看起來很有趣。 – 2009-09-26 12:35:54

+0

對不起,不接受你的答案,但我不想測試GUI,我只想測試我的模型沒有問題。 – 2009-09-27 12:59:35

2

檢查uispec4j項目。這就是我用來測試我的用戶界面。

www.uispec4j.org

+0

看起來像一個......失效的項目? (鏈接似乎不再去往哪裏) – Snappawapa 2018-01-26 01:58:26

1

我只用JMock的工作兩天......所以請原諒我,如果有一個更優雅的解決方案。 :)

它似乎像你的FileTableModel取決於SwingUtilities ...你有沒有考慮嘲笑你使用的SwingUtilities?一種聞起來像是破解但可以解決問題的方法是創建一個接口,比如說ISwingUtilities,並實現一個虛擬類MySwingUtilities,它簡單地轉發給真正的SwingUtilities。然後在你的測試案例中,你可以模擬接口並返回isEventDispatchThread的true。

@Test 
public void testEventsNow() throws IOException { 
    IFile testDir = mockDirectoryStructure(); 

    final ISwingUtilities swingUtils = context.mock(ISwingUtilities.class); 

    final FileSystemEventsListener listener = 
       context.mock(FileSystemEventsListener.class); 

    context.checking(new Expectations() 
    {{ 
     oneOf(swingUtils).isEventDispatchThread(); 
      will(returnValue(true)); 

     oneOf(listener).currentDirectoryChanged(with(any(IFile.class))); 
    }}); 

    FileTableModel model = new FileTableModel(testDir); 
    model.setSwingUtilities(swingUtils); // or use constructor injection if you prefer 
    model.switchToInnerDirectory(1); 
} 
+0

這基本上就是我們如何做到的。我們將SwingUtilities替換爲OurSwingUtilities.getInstance(),然後在測試中,我們有一個替代實現(我們不使用jMock,因爲很多測試可以更方便地共享一個類。)我們爲SwingWorker.execute ()以及Java庫中靜態的大量實用程序。 – Trejkaz 2013-01-30 03:54:59

2

我想與測試問題揭示與代碼中的問題。模型的工作不應該是決定它是否在調度線程中運行,這是太多的責任。它應該只做它的通知工作,並讓調用組件決定是直接調用它還是調用invokeLater。該組件應該位於知道Swing線程的代碼部分。這個組件應該只知道文件等。