2009-09-26 2 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 всегда трудно, потому что вы должны дразнить из много материала, который просто не доступен.
Поэтому основная цель при разработке приложений (любого типа) - всегда стараться как можно больше отделять элементы пользовательского интерфейса от основной логики приложения. Имея сильные зависимости здесь, сделайте модульное тестирование действительно тяжелым, в основном кошмар. Обычно это используется при использовании шаблонов типа MVC, где вы в основном тестируете свои классы контроллеров, а классы просмотра ничего не делают, кроме создания пользовательского интерфейса и делегирования своих действий и событий контроллерам. Это отделяет обязанности и облегчает тестирование.

Кроме того, вы не должны обязательно проверять вещи, которые уже предусмотрены каркасом, например, проверять, правильно ли запущены события. Вы должны просто проверить логику, которую вы пишете сами.

+1

Я написал этот co, и я хочу проверить, что он запускает события, когда это необходимо, и с правильными параметрами.Я думаю, что я делаю неправильно здесь, это обеспечить поток GUI внутри модели. Модель не является компонентом Swing, ей не нужно запускать события внутри потока графического интерфейса. Думаю ли я здесь правильно? –

12

Посмотрите this:

FEST представляет собой набор библиотек, выпущенный под Apache 2.0 license, чья миссия состоит в том, чтобы упростить тестирование программного обеспечения. Она состоит из различных модулей, которые могут быть использованы с TestNG или JUnit ...

+0

Выглядит интересно. –

+0

Извините, что не принимал ваш ответ, но я действительно не хочу тестировать графический интерфейс, я просто хочу проверить свою модель без проблем. –

2

Проверить проект uispec4j. Это то, что я использую для тестирования своих пользовательских интерфейсов.

www.uispec4j.org

+0

похоже на ....... неработающий проект? (ссылка больше не идет туда, где она была раньше) – Snappawapa

1

Я только работал с JMock в течение двух дней ... поэтому, пожалуйста, простите меня, если есть более элегантное решение. :)

Кажется, что ваш FileTableModel зависит от SwingUtilities ... вы считали насмешкой над SwingUtilities, которые вы используете? Один из способов, который пахнет взломом, но решит проблему, - это создать интерфейс, скажем, ISwingUtilities, и реализовать фиктивный класс MySwingUtilities, который просто перейдет в реальный SwingUtilities. А затем в тестовом примере вы можете макетировать интерфейс и возвращать true для isEventDispatchThread.

@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

2

Я думаю, что проблема с тестированием выявляет проблему с кодом. На самом деле не должно быть задачей модели решать, работает ли она в потоке отправки, это слишком много обязанностей. Он должен просто выполнить свое задание на уведомление и позволить вызывающему компоненту решить, следует ли его вызывать напрямую или invokeLater. Этот компонент должен быть частью кода, который знает о потоках Swing. Этот компонент должен знать только файлы и т. Д.

Смежные вопросы