5/11/2007

 

Why Do We Need Mock Framework?

Given we have a simple behavior to test: a form a text field on the form a button on the form click the button, should set the text of the text field to "Hello" And, here is the code implementing the behavior, MVP pattern is applied here:
public interface View {
  public void setText(String text);
  public void addActionListener(ActionListener actionListener);
}
public class Presenter {
  public Presenter(final View view) {
    view.addActionListener(new ActionListener() {
      public void actionPerformed() {
        view.setText("Hello");
      }
    });
  }
}
Before writing the test in java, let's first write in pseudo-code:
create mock view
create presenter by mock view
fire event on mock view
assert text is set
Then, let's implement it using latest jMock:
@Test
public void test_click_button_should_set_text_hello() {
  Mockery mockery = new Mockery();
  final View mockView = mockery.mock(View.class);
  final ActionListenerMatcher actionListenerMatcher = new ActionListenerMatcher();
  mockery.checking(new Expectations() {
    {
      one(mockView).addActionListener(with(actionListenerMatcher));
      one(mockView).setText("Hello");
    }
  });
  new Presenter(mockView);
  actionListenerMatcher.fireActionPerformed();
  mockery.assertIsSatisfied();
}
Here, we introduced a custom matcher, called ActionListenerMatcher. The reason why we need this, is because we need a way to fire the event. Without the matcher, we have no place to store the listener passed in. Here is the implementation of ActionListenerMatcher:
public class ActionListenerMatcher extends BaseMatcher {
  private ActionListener actionListener;
  public boolean matches(Object item) {
    actionListener = (ActionListener) item;
    return true;
  }
  public void fireActionPerformed() {
    actionListener.actionPerformed();
  }
  public void describeTo(Description description) {
  }
}
What is the conclusion? The intention of developer when writing the test is lost in the long and complex mocking code. How about other frameworks? I have tried EasyMock as well, which is even worse than jMock. Do we have a simpler way? Yes, we have. Check this out:
@Test
public void test_click_button_should_set_text_hello() {
  MockView mockView = new MockView();
  new Presenter(mockView);
  mockView.fireActionPerformed();
  Assert.assertEquals("Hello", mockView.getText());
}
Isn't this simple? MockView is just a simple implementation of View:
private class MockView implements View {
  private ActionListener actionListener;
  private String text;
  public void addActionListener(ActionListener actionListener) {
    this.actionListener = actionListener;
  }
  public void setText(String text) {
    this.text = text;
  }
  public String getText() {
    return text;
  }
  public void fireActionPerformed() {
    actionListener.actionPerformed();
  }
}
So, before you starting to use a mock framework. Think about it, do we really need them?

This page is powered by Blogger. Isn't yours?

Subscribe to Posts [Atom]