2012-07-01 35 views
4

我試圖熟悉TDD和演示者優先模式。現在我堅持爲我的Presenter.class編寫測試用例。我的目標是覆蓋包括Action Event在內的整個Presenter.class,但我沒有膠水如何與Mockito做到這一點。爲演示者類撰寫Mockito測試(演示者優先模式)

Presenter.class:

public class Presenter { 
IModel model; 
IView view; 

public Presenter(final IModel model, final IView view) { 
    this.model = model; 
    this.view = view; 

    this.model.addModelChangesListener(new AbstractAction() { 
     public void actionPerformed(ActionEvent arg0) { 
      view.setText(model.getText()); 
     } 
    }); 
}} 

IView.class:

public interface IView { 
    public void setText(String text); 
} 

IModel.class:

public interface IModel { 
    public void setText(); 
    public String getText(); 
    public void whenModelChanges(); 
    public void addModelChangesListener(AbstractAction action); 
} 

PresenterTest.class:

@RunWith(MockitoJUnitRunner.class) 
public class PresenterTest { 

    @Mock 
    IView view; 
    @Mock 
    IModel model; 

    @Before 
    public void setup() { 
     new Presenter(model, view); 
    } 

    @Test 
    public void test1() { 
    } 
} 

在此先感謝!

回答

1

起初......謝謝你們!

過了一會兒,我想通了,這個解決方案,並堅持它,因爲我不希望在演示類實現任何接口,無論是我想在我的測試創建存根類。

IVIEW

public interface IView { 
    public void setText(String text); 
} 

IModel

public interface IModel { 
    public String getText(); 
    public void addModelChangeListener(Action a); 
} 

演示

public class Presenter { 

    private IModel model; 
    private IView view; 

    public Presenter(final IModel model, final IView view) { 
     this.model = model; 
     this.view = view; 

     model.addModelChangeListener(new AbstractAction() { 
      public void actionPerformed(ActionEvent e) { 
       view.setText(model.getText()); 
      } 
     }); 
    } 
} 

PresenterTest

@RunWith(MockitoJUnitRunner.class) 
public class PresenterTest { 

    @Mock 
    IView view; 

    @Mock 
    IModel model; 

    @Test 
    public void when_model_changes_presenter_should_update_view() { 
     ArgumentCaptor<Action> event = ArgumentCaptor.forClass(Action.class); 

     when(model.getText()).thenReturn("test-string"); 
     new Presenter(model, view); 
     verify(model).addModelChangeListener(event.capture()); 
     event.getValue().actionPerformed(null); 
     verify(view).setText("test-string"); 
    } 
} 
0

在這種情況下,模型和主持人之間的連接是足夠鬆(通過一個動作監聽通信),你很可能關閉不使用的模型模擬更好。

你可以使用一個真實模型(我寧願,如果真實模型是很簡單的),或者我在下面的代碼片段,讓你的測試代碼內部的存根。

@RunWith(MockitoJUnitRunner.class) 
public class PresenterTest { 

    @Mock 
    IView view; 

    IModel model; 

    @Before 
    public void setup() { 
     model = new StubModel(); 
     new Presenter(model, view); 
    } 

    @Test 
    public void presenterUpdatesViewWhenModelChanges() { 
     model.setText("Test Text"); 
     verify(view).setText("Test Text"); 
    } 

    private class StubModel implements IModel { 
     private String text; 
     private List<ActionListener> actionListeners; 

     StubModel() { 
      actionListeners = new ArrayList<ActionListener>(); 
     } 

     @Override 
     public void setText(String text) { 
      this.text = text; 
      whenModelChanges(); 
     } 

     @Override 
     public String getText() { 
      return text; 
     } 

     @Override 
     public void whenModelChanges() { 
      for (ActionListener listener: actionListeners) { 
       listener.actionPerformed(null); 
      } 
     } 

     @Override 
     public void addModelChangesListener(AbstractAction action) { 
      actionListeners.add(action); 
     } 
    } 
} 

這是可能的,你可以設置此測試與模擬模型上,您設置存根調用,但要做到這一點理智,你可能還需要一個模擬行動,這將複雜的事情,因爲在創建行動由主持人。

這看起來像是很多測試代碼,用於測試演示者類中的一行代碼,但最大的塊是存根模型,它可能被真實模型替代或從此測試類中提取出來並共享與其他測試。

+0

謝謝喲你不要回答。如果我的三元組變得更加複雜並且我不想創建如此大的存根,它會如何?沒有任何方法可以捕獲Action,執行並驗證它嗎? – Oliver

+0

存根的原因是,在您的當前代碼中,'AbstractAction'是在'Presenter'代碼中創建的。如果它是由注入的工廠注入或者可能由注入的工廠創建的,那麼您可以嘲笑該模型以及使用mockito對存根進行存根。不太明確的編碼存根和更多的模擬存根......還有一種方法可以捕獲參數,這可能允許您僅使用模擬。當我有更多的時間時,我可能會試着詳細說明,或者也許有人用Mockito實際上使用了參數捕獲來嵌入。 –

0

這是一個小的重構可以走很長的路。學會「聆聽」測試並讓他們推動設計。 Model只需要知道需要通知ActionListener,它並不在乎它是否是AbstractAction。在班級合同中使用可能的最小接口。這裏是做一個簡單的測試重構(可能過於簡單,不值得單元測試,但你的想法):

Presenter.class:

public class Presenter { 
    public Presenter(final IModel model, final IView v) implements ActionListener { 
    this.model = model; 
    this.view = v; 
    model.addModelChangesListener(this); 
    } 

    public void actionPerformed(ActionEvent arg0) { 
    view.setText(model.getText()); 
    } 
} 

IModel.class:

public interface IModel { 
    public void addModelChangesListener(ActionListener action); 
} 

PresenterTest.class:

@RunWith(MockitoJUnitRunner.class) 
public class PresenterTest { 
    @Mock IView view; 
    @Mock IModel model; 

    @Test 
    public void when_model_changes_presenter_should_update_text() { 
     when(model.getText()).thenReturn("Test Text"); 
     Presenter p = new Presenter(model, view); 
     p.actionPerformed(null); 
     verify(view).setText("Test Text"); 
    } 
} 
相關問題