27 March 2020

TDD an Immediate Mode UI

Today I continue my experiments with test driving user interfaces. First I looked at test driving classic, fat, state based UIs like Swing or WinForms and later web component libraries like Vaadin. I need to explore different programming environments and platforms to see what is possible. In this post I want to have a look at immediate mode GUIs. An immediate mode GUI is a GUI where the event processing is directly controlled by the application. When I first read a similar sentence on Wikipedia, it did not help me at all. So what is an immediate mode GUI?

User InterfaceRetained Mode
A better question would be "what is retained mode?" Wikipedia states that retained mode is a style of API design in which the graphics library retains the complete object model of the rendering primitives to be rendered. That means that the widget, e.g. an instance of a JButton, contains all state needed to draw the button, i.e. colours, position, is the button clicked and so forth. When the button is created, or even "drawn", it is not causing the actual rendering. The GUI library decides when and how to render the widget and optimises the actual rendering. This includes double buffering, clipping or partial updates. Retained mode is the dominant style in GUI libraries, all user interfaces you have build were likely of this style.

Immediate Mode
So let's get back to Immediate mode. When using an immediate mode GUI library, the event processing is directly controlled by the application. There is no button object, there is just a Button(bounds Rectangle, text string) function which immediately draws the button with given text at the given position and size (argument bounds). The function returns true if the button was clicked. The application code must call all drawing commands required to describe the entire scene each time a new frame is displayed. This is often used in video games programming and examples of immediate mode rendering systems include Direct2D and OpenGL. If you want to know more about this mode, see this list of immediate mode gui tutorials on StackOverflow.

The (immediate mode) UI framework I am going to use is raylib, a simple and easy to use library to enjoy video games programming. See its cheat sheet for an overview of its functions. It has a simple API which hides everything regarding windowing system and environment. I am writing code in Go, so I am using raylib-go, the Golang bindings for raylib. Honestly I have no idea what I am doing. I have never used an immediate mode framework, not even heard of one before last year. In addition I know little to nothing about the Go language. Nevertheless I managed to talk my fellow crafter, Extreme Programmer and probably Vienna's longest time Go practitioner, Christian Haas into running this experiment with me. We spent one full day working on the Login Form exercise.

The first test: There is a button
import (
  "testing"
  ...
  rl "github.com/gen2brain/raylib-go/raylib"
)

func TestForm_LoginButton(t *testing.T) {
  var form login.Form
  ui := newTestingUI()

  form.Render(ui)

  if !ui.buttonCalled {
    t.Errorf("Button() was not called")
  }
}
Form is the struct containing the form's data, which is empty for now. Render is a receiver function on the form, which creates a button with no bounds and an empty text.
type Form struct{}

func (form Form) Render(ui FormUI) {
  ui.Button(rl.Rectangle{}, "")
}
To check that certain calls into raylib have been made, there is an interface FormUI between the application code and raylib. In the tests this interface is mocked to verify certain calls have been made. (In Go an interface type is defined as a set of method signatures. This is the way to achieve polymorphism.)
type testingUI struct {
  buttonCalled bool
}

func (ui *testingUI) Button(bounds rl.Rectangle, text string) bool {
  ui.buttonCalled = true
  return false
}
This follows an approach I have found as a possible TDD approach:
  • Design and write your methods separated from the actual UI.
  • TDD the elements and behaviour.
  • Mock single UI elements to verify necessary calls but do not show them.
For Swing I cannot see how this approach would be practical, but in this example with immediate mode raylib, it feels natural.

More Code
Soon the number of interactions with the UI made it necessary to add string ids to each drawing primitive. While raylib did not need them, other libaries do, so it did not feel wrong to add them. The mocked UI was growing. Here are the final pieces of code for the login button.
type testingUI struct {
  // verify if Button method has been called (mock)
  buttonCalled  map[string]bool

  // record button's text and bounds for later inspection (spy)
  buttonText    map[string]string
  buttonBounds  map[string]rl.Rectangle

  // return value of the Button method = user interaction (stub)
  buttonResults map[string]bool

  ...
}

func newTestingUI() *testingUI {
  ui := &testingUI{
    buttonCalled:  make(map[string]bool),
    buttonText:    make(map[string]string),
    buttonBounds:  make(map[string]rl.Rectangle),
    buttonResults: make(map[string]bool),
    ...
  }
  return ui
}

func (ui *testingUI) Button(id string, bounds rl.Rectangle, text string) bool {
  ui.buttonCalled[id] = true
  ui.buttonText[id] = text
  ui.buttonBounds[id] = bounds
  result := ui.buttonResults[id]
  ui.buttonResults[id] = false // reset button click after first call
  return result
}

func TestForm_LoginButton(t *testing.T) {
  var form login.Form
  ui := newTestingUI()

  form.Render(ui)

  if !ui.buttonCalled["login"] {
    t.Errorf("not found")
  }
}

func TestForm_LoginButtonText(t *testing.T) {
  var form login.Form
  ui := newTestingUI()

  form.Render(ui)

  if "Log in" != ui.buttonText["login"] {
    t.Errorf("is not \"Log in\"")
  }
}

func TestForm_LoginButtonBounds(t *testing.T) {
  var form login.Form
  ui := newTestingUI()

  form.Render(ui)

  expectedBounds := rl.Rectangle{300, 165, 110, 30}
  if ui.buttonBounds["login"] != expectedBounds {
    t.Errorf("expected %v, but was %v", expectedBounds, ui.buttonBounds)
  }
}
and the production code
type FormUI interface {
  Button(id string, bounds rl.Rectangle, text string) bool
  ...
}

func (form *Form) Render(ui FormUI) bool {
  buttonBounds := rl.Rectangle{X: 300, Y: 165, Width: 110, Height: 30}
  if ui.Button("login", buttonBounds, "Log in") {
    // TODO authenticate
  }

  return false
}
The third test, TestForm_LoginButtonBounds checks the position and size of the button. These properties are considered "layout". I do not like to test layout. I had to open GIMP to decide on the proper rectangle in expectedBounds, which I really dislike. I also expect this values to change a lot during initial development. Additionally Rectangle is a raylib type and so we depend on raylib in our code. Other options would have been:
  • Ignore layout completely. But then we would need to revisit all calls and add the Rectangles later.
  • Use abstract coordinates, i.e. map my coordinates into raylib Rectangles. That seemed like an extra overhead.
  • Move the responsibility of layout into the wrapper. There would be a button method for each button in the application and there would be more code outside my tests.
  • Move out the bounds and store them in the wrapper with a simple lookup on the id. Moving out stuff is against the nature of Immediate mode because the whole UI is expected to be in the code.
The wrapper for raylib is straight forward.
type RaylibFormUI struct{}

func (ui *RaylibFormUI) Button(id string, bounds rl.Rectangle, text string) bool {
  return raygui.Button(bounds, text)
}
This should give you an idea how things worked out. If you want to follow our TDD steps, here are the individual commits.

Is this MVP?
The MVP (Model View Presenter pattern) has a very thin, dumb UI, which is called the view. The model contains the UI data or UI model which might contain information about enabled fields, active buttons and so on. The presenter is a mediator and wires the model and the view. In the Go code above, the Form structure could be seen as an UI model. Later it will hold the user name and password data. The form receiver function func (form *Form) Render(ui FormUI) bool contains the presenter logic. It is not a separate object - there are no objects in Go - but it could be separate. Due to the immediate mode UI, there are no callbacks from the view in case of events. This removes the need for the usual MVP event listeners. The FormUI interface is like a MVP view as it hides the raylib dependency. It does not abstract away the underlying library, it is just a thin wrapper. It is not a MVP view. It could be made a view, i.e. provide more abstract functions in domain language, and then it would need tests on its own. In the experiment, this seemed unnecessary. In the end the FormUI will delegate many functions to raylib, so it could be generated from its original source code. This shows the tight coupling of the FormUI and the underlying UI library.

Water PressureConclusion
We built a login user interface following the requirements using Test Driven Development. It was easy and we did not face any problems, so no big deal. The Immediate mode library made it easier than for retained mode: There was no need to search for components, capture events, trigger events and so forth, definitely easier than my initial experiment. When comparing these experiments for Swing and raylib, I am reminded of the difference of Classic and Mockist TDD. In retained mode, e.g. Swing, I kept checking the state of UI components while in immediate mode I verified expected calls of the library. This approach allows variable depth of checks. We could have asserted colours and styles and we did not. So we will have to look at the finished form in the end. Christian proposed saving the image of the final view and storing it for regression testing.

We used TDD but there was little pressure on the design of the code. There was some pressure on the design of the API of Form, but there was no pressure on its internal workings nor on FormUI at all. The tests drove the creation of the UI - which was dictated by the requirements - there was no space for evolution. A different (UI) design might have been easier to test, but that was not an option. (A different UI would not have been different to test in this example anyway.) So we lost this particular benefit of TDD.

Try it yourself
I will continue my experiments and I would like to hear your ideas on the topic. The Go starting code with raylib-Go, its required dependencies and linter setup is available in the Login Form Kata. Try it yourself!

4 March 2020

TDD a Vaadin UI

As Code Cop I am working to get teams into adopting TDD. I use a mixture of classic training, guided workshops, Coding Dojos, code reviews and coaching to make this happen. One of my clients is working with Vaadin and keeps using it as an excuse to not use TDD. Not good. After my recent experiments with test driving user interfaces I "hijacked" one of our mob programming sessions and we worked on the Login Form Kata.

Vaadin
The client uses Vaadin 8 and the web has several ideas how to test (drive) it:
  • Use the Model View Presenter pattern, see Vaadin Advanced Application Architectures.
  • Gradually separate the UI from the logic, thinking of MVP more as a process than a pattern, starting with separate methods, which are accessible to tests so that the test can invoke them. For more details see Is MVP a Best Practice?
  • Create factories for all UI components so that tests can mock the UI. See this answer on StackOverflow for more details.
  • Running integrated tests in a test bed to simulate UI.​getCurrent() or VaadinSession.​getCurrent(), e.g. using the Karibu-Testing library.
LoginPresenter
We used MVP as described in my previous article. The group decided against a view model, because there was no specific UI model. Next was the presenter. The first two tests made us implement the requirement for a successful login: User name and password given, button "Log in" clicked, back end reports success, then the form is closed.
import org.mockito.Mockito;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class LoginPresenterTest {

  public static final String USERNAME = "Peter";
  public static final String PASSWORD = "Slovakia";

  private AuthenticationService authenticationService;
  private NavigatorView navigatorView;
  private LoginView loginView;
  private ExecutorService executorService;

  private LoginPresenter loginPresenter;

  @BeforeEach
  public void init() {
    authenticationService = Mockito.mock(AuthenticationService.class);
    navigatorView = Mockito.mock(NavigatorView.class);
    loginView = Mockito.mock(LoginView.class);
    executorService = Executors.newSingleThreadExecutor();

    loginPresenter = new LoginPresenter(authenticationService, navigatorView,
                                        loginView, executorService);
  }

  @Test
  public void should_call_backend_on_button_click() throws InterruptedException {
    Mockito.when(authenticationService.authenticate(USERNAME, PASSWORD))
      .thenReturn(new AuthenticationResult(true, "we do not care!"));

    loginPresenter.login(USERNAME, PASSWORD);
    waitForAuthentification();

    Mockito.verify(authenticationService, Mockito.times(1))
      .authenticate(USERNAME, PASSWORD);
  }

  @Test
  public void should_navigate_on_login_success() throws InterruptedException {
    Mockito.when(authenticationService.authenticate(USERNAME, PASSWORD))
      .thenReturn(new AuthenticationResult(true, "we do not care!"));

    loginPresenter.login(USERNAME, PASSWORD);
    waitForAuthentification();

    Mockito.verify(navigatorView, Mockito.times(1))
      .navigateToDashBoard();
  }

  private void waitForAuthentification() throws InterruptedException {
    executorService.shutdown();
    executorService.awaitTermination(1, TimeUnit.SECONDS);
  }
Using an ExecutorService made the asynchronous execution pretty simple. I like how they wrote two tests for the different aspects of successful login. Using smaller steps helped to get some logic sooner. It turned out that we needed another component for navigation, so we made up the NavigatorView. Then we went for the requirements User name and password given, button "Log in" clicked, back end reports an error, show message in error line, form stays open and While the back end is working, the "Log in" button stays disabled.
import org.mockito.InOrder;
import static org.mockito.ArgumentMatchers.any;

...

  @Test
  public void should_display_error_on_login_error() throws InterruptedException {
    String errorMessage = "error message";
    Mockito.when(authenticationService.authenticate(USERNAME, PASSWORD))
      .thenReturn(new AuthenticationResult(false, errorMessage));

    loginPresenter.login(USERNAME, PASSWORD);
    waitForAuthentification();

    Mockito.verify(navigatorView, Mockito.never())
      .navigateToDashBoard();
    Mockito.verify(loginView, Mockito.times(1))
      .displayErrorMessage(errorMessage);
  }

  @Test
  public void should_register_to_view() {
    Mockito.verify(loginView, Mockito.times(1))
      .addListener(any(LoginListener.class));
  }

  @Test
  public void should_disable_button_while_backend_is_working() throws InterruptedException {
    Mockito.when(authenticationService.authenticate(USERNAME, PASSWORD))
      .thenReturn(new AuthenticationResult(false, "we do not care!"));

    loginPresenter.login(USERNAME, PASSWORD);

    InOrder inOrder = Mockito.inOrder(loginView);
    inOrder.verify(loginView).setLoginButtonEnabled(false);
    waitForAuthentification();
    inOrder.verify(loginView).setLoginButtonEnabled(true);
  }
}
The finished presenter class looked almost like the one for Swing.
import java.util.concurrent.ExecutorService;

public class LoginPresenter implements LoginListener {

  private final AuthenticationService authenticationService;
  private final NavigatorView navigatorView;
  private final LoginView loginView;
  private final ExecutorService executorService;

  public LoginPresenter(AuthenticationService authenticationService,
                        NavigatorView navigatorView, LoginView loginView,
                        ExecutorService executorService) {
    this.authenticationService = authenticationService;
    this.navigatorView = navigatorView;
    this.loginView = loginView;
    this.executorService = executorService;

    loginView.addListener(this);
  }

  @Override
  public void login(String username, String password) {
    loginView.setLoginButtonEnabled(false);
    executorService.submit(() -> invokeLoginService(username, password));
  }

  private void invokeLoginService(String username, String password) {
    AuthenticationResult authenticate =
      authenticationService.authenticate(username, password);
    loginView.setLoginButtonEnabled(true);
    if (authenticate.success) {
      navigatorView.navigateToDashBoard();
    } else {
      loginView.displayErrorMessage(authenticate.message);
    }
  }
}
And the presenter would hide behind the LoginListener interface.
public interface LoginListener {

  void login(String username, String password);

}
Test Bed
As for the Swing version, using a test bed helped testing the view. There is a useable Vaadin testing tool, the Karibu-Testing library. It worked out of the box, no special treatment necessary. We wrote tests that the view forwards actions to the LoginListener, i.e. the LoginPresenter, and that the view can display an error message.
import com.github.mvysny.kaributesting.v8.MockVaadin;
import com.vaadin.ui.Button;
import com.vaadin.ui.Label;
import com.vaadin.ui.TextField;
import org.mockito.Mockito;

import static com.github.mvysny.kaributesting.v8.LocatorJ.*;

class LoginViewTest {

  private final LoginViewImpl content = new LoginViewImpl();

  @BeforeEach
  void beforeEach() {
    MockVaadin.setup(() -> new HelloUI(content));
  }

  @AfterEach
  void afterEach() {
    MockVaadin.tearDown();
  }

  @Test
  void should_pass_on_button_click() {
    LoginListener loginListener = Mockito.mock(LoginListener.class);
    content.addListener(loginListener);

    // simulate a text entry as if entered by the user
    _setValue(
      _get(TextField.class, spec -> spec.withCaption("Phone, email or username")),
      "peter");

    _setValue(
      _get(TextField.class, spec -> spec.withCaption("Password")),
      "Slovakia");

    // simulate a button click as if clicked by the user
    _click(_get(Button.class, spec -> spec.withCaption("Log in")));

    Mockito.verify(loginListener).login("peter", "Slovakia");
  }

  @Test
  void should_display_error_message() {
    content.displayErrorMessage("myError message");

    // simulate a text entry as if entered by the user
    Label label = _get(Label.class, spec -> spec.withValue("myError message"));

    Assertions.assertEquals(label.getStyleName(), "warning");
  }
}
Satisfying these two tests gave us the following view:
import com.vaadin.ui.*;

public class LoginViewImpl extends VerticalLayout implements LoginView {

  private final TextField username = new TextField("Phone, email or username");
  private final TextField password = new PasswordField("Password");
  private final Button loginButton = new Button("Log in");
  private final Label errorLabel = new Label();

  public LoginViewImpl() {
    addComponent(username);
    addComponent(password);
    addComponent(loginButton);
    addComponent(errorLabel);
    errorLabel.setStyleName("warning");
  }

  @Override
  public void addListener(LoginListener loginListener) {
    loginButton.addClickListener(clickEvent -> {
      loginListener.login(username.getValue(), password.getValue());
    });
  }

  @Override
  public void displayErrorMessage(String errorMessage) {
    errorLabel.setValue(errorMessage);
  }

  // ...
}
That was as far as we went during the sessions. We did not finish the whole login window, next tests would drive the logic of setLoginButtonEnabled(boolean).

Conclusion
Besides small differences, the code looks much like the Swing version. The process worked the same, most tests do not deal with the UI. As I do not know many UI frameworks my conclusion is limited. Maybe - hopefully - probably this approach works for state based user interfaces as long as there is a reasonable test bed. I can see how it could work for C# WinForms. On the other hand, Vaadin and WinForms are very similar to Java's Swing. I need to look at other kind of user interfaces.

7 February 2020

TDD Classic State Based UI

Most modern user interface technologies are state based. Classic frameworks like Swing, JavaFX, Eclipse RCP, Windows Forms, Vaadin and many more consist of heavy weight UI widgets that manage all their state and interact with the application using event handlers. Such frameworks are harder to test than plain code. I have not found much information on how to do that, one resource that got me started is chapter eight from Lasse Koskela's Test Driven. I am using many ideas from that book in here.

Model View Presenter (MVP) Pattern
Because these UI technologies are heavy weight, hard to test and often slow to run, one needs to decouple from them as much as possible. The goal is to minimize all UI dependencies. As few classes as possible should be "contaminated" with UI stuff, and the code that needs to do UI should contain as little logic as possible. Common ways to separate concerns between the interface and the underlying logic are MVC, MVP, MVVM or similar architectural patterns. I am using the MVP pattern. Its goal is - obviously - to facilitate automated unit testing and improve the separation of concerns in presentation logic. That means MVP is used to have a very thin, dumb UI, which is called the view. The model contains the UI data or UI model which might contain information about enabled fields, active buttons and so on. The presenter is a mediator and wires the model and the view.

Using Java and Swing
On my research on how to test drive user interfaces I started with Java and Swing. The Wikipedia page lists several UI frameworks which use the MVP patterns themselves, Swing being one of them. That means that Swing uses MVP internally. Larger components like JComboBox or JTable have their own model classes ComboBoxModel and TableModel. This is useful because the models do not depend on the user interface part of Swing and can be TDD'ed in the usual way. It does not mean that Swing can be test driven easily. As example I will run my Login Form Kata. I am going to develop the basic login screen step by step using TDD.

First Test: LoginModel should contain user lookup and password
I start with the model. The model contains the state of the user interface. There is no problem using TDD for that. My first test is
class LoginModelTest {

  LoginModel model = new LoginModel();

  @Test
  void shouldContainUserLookupAndPassword() {
    model.setLookup("user@server.com");
    model.setPassword("secret123");

    assertEquals("user@server.com", model.getLookup());
    assertEquals("secret123", model.getPassword());
  }
}
After seeing it red, I add
public class LoginModel {

  private String lookup;
  private String password;

  // getters and setters for lookup and password
}
Green. Usually I am not testing for getters and setters, but today I have to start somewhere. Depending on the used version of MVP, the model could update the view itself. I choose to keep the model very simple, following the Passive View aka Humble Dialog Box variant of MVP. This seems to be the usual way. In this example of login form, there is no state that goes back from the model into the view yet, e.g. if the login button should be disabled, so it does not make any difference.

Test: LoginPresenter should pass lookup and password to its model
Next is line is the LoginPresenter. The presenter is handling all user input. It is important, that the presenter has no dependency on Swing, too, so there is no problem TDDing that. The presenter will be notified of user input into the lookup or password field and will store the values in the model.
class LoginPresenterTest {

  LoginModel model = new LoginModel();
  LoginPresenter presenter = new LoginPresenter(model);

  @Test
  void shouldPassLookupAndPasswordToModel() {
    presenter.lookupChanged("user");
    presenter.passwordChanged("pass");

    assertEquals("user", model.getLookup());
    assertEquals("pass", model.getPassword());
  }
}

public class LoginPresenter {

  private final LoginModel model;

  public LoginPresenter(LoginModel model) {
    this.model = model;
  }

  public void lookupChanged(String newLookup) {
    model.setLookup(newLookup);
  }

  public void passwordChanged(String newPassword) {
    model.setPassword(newPassword);
  }
}

Empty LoginView
Finally I create the LoginView interface. The view wraps the UI technology completely. It starts as an empty interface. The methods to come will be driven by the needs of the presenter.
public interface LoginView { }

Test: LoginPresenter should close the view on successful login
It is time to go for some real logic. When the login button is clicked, the authentication back end will be called and if the call was successful, the view should be closed. The test uses Mockito to mock the view and verify it has been called.
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

class LoginPresenterTest {

  LoginModel model = new LoginModel();
  LoginView view = mock(LoginView.class);
  AuthenticationService auth = mock(AuthenticationService.class);

  LoginPresenter presenter = new LoginPresenter(model, view, auth);

  @Test
  void shouldCloseViewOnSuccessLogin() {
    model.setLookup("user");
    model.setPassword("secret");
    when(auth.authenticate("user", "secret")).
      thenAnswer(invocation -> {
        return new AuthenticationResult(true, null);
      });

    presenter.loginButtonClicked();

    verify(view).close();
  }
}
This adds a close() method to the LoginView. Because I own the view, I can use domain names and the actual UI technology is not visible from the outside.

Test: LoginPresenter should display an error on failed login
Another test drives the display of an error message if authentication fails. This creates a showError(String message) method in the view.
  @Test
  void shouldDisplayErrorOnFailedLogin() {
    model.setLookup("user2");
    model.setPassword("secret2");
    when(auth.authenticate("user2", "secret2")).
      thenAnswer(invocation -> {
        return new AuthenticationResult(false, "Login failed.");
      });

    presenter.loginButtonClicked();

    verify(view).showError("Login failed.");
  }
And so the loginButtonClicked method is complete.
  public LoginPresenter(LoginModel model, LoginView view,
                      AuthenticationService authenticationService) {
    this.model = model;
    this.view = view;
    this.authenticationService = authenticationService;
  }

  @Override
  public void loginButtonClicked() {
    AuthenticationResult result =
      authenticationService.authenticate(model.getLookup(), model.getPassword());
    if (result.success) {
      view.close();
    } else {
      view.showError(result.message);
    }
  }

Test: LoginPresenter should call Authentication service asynchronously
As stated in the requirements, all calls to the back end need to be asynchronous. Synchronous code would block the Swing event thread and render the UI unresponsive. So I change the tests to force the calls to be asynchronous. I need two java.​util.​concurrent.​CountDownLatchs and have to wait on them to start and finish asynchronous processing.

Test Bed
The last piece is the view - the implementation of the view to be precise. To test the real view it has to be started and sent some events. This is what I wanted to avoid. It is slow and brittle. By following the MVP pattern described above, the view will have as little code as possible. There will only be a few tests executing it. Sometimes it is necessary to call certain methods on UI classes for the UI to work at all, e.g. show. It is not pretty. Best would be to use a test bed or harness to run these UI components in an isolated way, e.g. to have a dedicated window for the component under test and to create the application in a way that allows to exercise UI features independently.

Lasse Koskela mentions Abbot to test stand alone AWT or Swing components. It provides helper code for finding and interacting with UI elements. See how Abbot works in one of its tutorials. It is pretty old and its test support is for JUnit 3, but it gets the job done. It displays a frame while running the tests and there are flickering tests from time to time. This is not a problem of Abbot itself, but is the nature of full UI tests. As I said, these are brittle.

Test: SwingLoginView has a login button with text
A basic start is to assert the existence of UI elements. Abbot offers several ways to find elements, using its getFinder().​find(...) method. An easy way to locate elements is to use ids or names, e.g. with loginButton.​setName("LoginButton").
import javax.swing.JButton;
import javax.swing.JPanel;

import abbot.finder.ComponentSearchException;
import abbot.finder.matchers.NameMatcher;
import junit.extensions.abbot.ComponentTestFixture;

public class SwingLoginViewTest extends ComponentTestFixture {

  LoginView view = new SwingLoginPanel();

  public SwingLoginViewTest(String name) {
    super(name);
  }

  public void testHasLoginButtonWithText() throws ComponentSearchException {
    showFrame((JPanel) view); // Abbot shows the view
    JButton loginButton = findLoginButton();

    assertEquals("Log in", loginButton.getText());
  }

  private JButton findLoginButton() throws ComponentSearchException {
    return (JButton) getFinder().find(new NameMatcher("LoginButton"));
  }
}
This tests forces me to create the initial login panel.
import javax.swing.JButton;
import javax.swing.JPanel;

public class SwingLoginPanel extends JPanel implements LoginView {

  private final JButton loginButton = new JButton("Log in");

  public SwingLoginPanel() {
    createLoginButton();
  }

  private void createLoginButton() {
    loginButton.setName("LoginButton");
    add(loginButton);
  }

  @Override
  public void close() {
  }

  // other empty LoginView methods

}

Observer Pattern
In MVP, the view delegates user input somewhere else and does nothing but rendering. We using the Observer Pattern to get notifications from the UI. The view takes the role of subject and the presenter is observing it. Observer Pattern subjects need to manage the list of observers - in Java usually named listeners - and allow code to register and sometimes deregister them.

Test: SwingLoginView should send button click to presenter
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import abbot.tester.JButtonTester;

...

  public void testSendButtonClickToPresenter() throws ComponentSearchException {
    LoginListener listener = mock(LoginListener.class);
    view.registerLoginListener(listener);

    showFrame((JPanel) view);
    JButton loginButton = findLoginButton();
    JButtonTester tester = new JButtonTester(); // from Abbot
    tester.actionClick(loginButton);

    verify(listener).loginButtonClicked();
  }
As I said, the presenter will be the actual observer, hiding behind the LoginListener interface.
public interface LoginListener {

  void loginButtonClicked();

}
Its implementation is straight forward.
  @Override
  public void registerLoginListener(LoginListener listener) {
    loginButton.addActionListener(ae -> listener.loginButtonClicked());
  }

Test: SwingLoginView has input fields for lookup and password
Like for the login button, I assert the existence of lookup and password fields and that they are wired to the listener. To verify that, the test code enters some text into the fields and checks that the listener mock has been called.
  public void testHasLookupField() throws ComponentSearchException {
    LoginListener listener = mock(LoginListener.class);
    view.registerLoginListener(listener);

    showFrame((JPanel) view);
    JTextField lookupField = findLookupField();

    assertEquals(20, lookupField.getColumns());

    // verify that it is wired as well
    JTextFieldTester tester = new JTextFieldTester(); // from Abbot
    tester.actionEnterText(lookupField, "user");

    verify(listener).lookupChanged("user");
  }

  private JTextField findLookupField() throws ComponentSearchException {
    return (JTextField) getFinder().find(new NameMatcher("LookupField"));
  }
Yes, this is not a good unit test as it tests two things - visible by its two checks, assert and verify. I should split that into two independent tests. Unfortunately these tests are slow, so I want to minimize their number. Together with a similar test for the JPasswordField passwordField the view is taking shape.
  private final JTextField lookupField = new JTextField(20);
  private final JPasswordField passwordField = new JPasswordField(20);

  private void createLookupField() {
    lookupField.setName("LookupField");
    add(lookupField);
  }

  private void createPasswordField() {
    passwordField.setName("PasswordField");
    add(passwordField);
  }

  @Override
  public void registerLoginListener(LoginListener listener) {
    lookupField.getDocument().
      addDocumentListener(new AllDocumentListener() {
        @Override
        protected void fire() {
          listener.lookupChanged(lookupField.getText());
        }
      });

    passwordField.getDocument().
      addDocumentListener(new AllDocumentListener() {
        @Override
        protected void fire() {
          listener.passwordChanged(new String(passwordField.getPassword()));
        }
      });

    loginButton.addActionListener(ae -> listener.loginButtonClicked());
  }
To be notified of each input character, I use Swing's DocumentListener. (AllDocumentListener is my own base class to handle the many methods of it.) This gives the final listener for the observer:
public interface LoginListener {

  void lookupChanged(String lookup);
  void passwordChanged(String password);
  void loginButtonClicked();

}

Test: SwingLoginView should display errors
This is the final test for the view.
  public void testErrorDisplay() throws ComponentSearchException, InterruptedException {
    showFrame((JPanel) view);
    JLabel errorField = findErrorField();

    assertEquals("", errorField.getText());

    view.showError("Alert!");
    Thread.sleep(10); // wait for asynchronous update

    assertEquals("Alert!", errorField.getText());
    assertEquals(Color.RED, errorField.getForeground());
  }

  private JLabel findErrorField() throws ComponentSearchException {
    return (JLabel) getFinder().find(new NameMatcher("ErrorField"));
  }
And the final SwingLoginView:
import java.awt.Color;

import javax.swing.JLabel;
import javax.swing.SwingUtilities;

...

  private static final Color ERROR_COLOR = new Color(255, 0, 0);
  private final JLabel errorField = new JLabel();

  private void createErrorField() {
    errorField.setName("ErrorField");
    errorField.setForeground(ERROR_COLOR);
    add(errorField);
  }

  @Override
  public void showError(String message) {
    SwingUtilities.invokeLater(() -> errorField.setText(message));
  }
SwingUtilities.invokeLater() is needed because showError is called asynchronously. While there is agreement in the TDD community to not assert on layout or styling, I am asserting that the foreground of the error field changed to an colour indicating the error, because it is important to indicate errors also in colour.

Test: LoginPresenter should register itself to the view
To complete the Observer Pattern, the presenter needs to register itself to the view. I started with verify(view).​registerLoginListener(​Mockito.​any(​LoginListener.class)); but that is not what I want. I really want that the methods on the listener trigger the required functionality in the back end or model.
import org.mockito.ArgumentCaptor;

...

  @Test
  void shouldRegisterItselfToView() throws InterruptedException {
    when(auth.authenticate(any(String.class), any(String.class))).
      thenReturn(new AuthenticationResult(true, null));

    ArgumentCaptor<LoginListener> argument = ArgumentCaptor.forClass(LoginListener.class);
    verify(view).registerLoginListener(argument.capture());
    LoginListener listener = argument.getValue();

    listener.lookupChanged("user");
    assertEquals("user", model.getLookup());

    listener.passwordChanged("pass");
    assertEquals("pass", model.getPassword());

    listener.loginButtonClicked();
    Thread.sleep(10);
    verify(auth).authenticate("user", "pass");
  }
When the presenter registers itself to the view, I capture the listener using Mockito's ArgumentCaptor. Then I call the listener and check the wanted behaviour. The sleep time is required because authentication is run asynchronously. Finally the presenter is complete.
public class LoginPresenter implements LoginListener {

  // ...

  public LoginPresenter(LoginModel model, LoginView view,
                        AuthenticationService authenticationService) {
    this.model = model;
    this.view = view;
    this.authenticationService = authenticationService;

    view.registerLoginListener(this);
  }

  // ...
}
and the final view (interface) is
public interface LoginView {

  void close();
  void showError(String message);
  void registerLoginListener(LoginListener listener);

}
The actual commits are here.

Conclusion
This was my first try and it worked well. I conclude that it is possible to TDD UIs at least using Java and Swing. I have working examples and the testing tools are fair. The final code has the usual TDD benefits - more separation between concerns (i.e. logic and UI technology) and a better design using domain methods. I tested the UI elements briefly. I did not go into test driving styling, colours or positions. In Swing components have all these properties accessible, e.g. visibility, colours, positions and more. So I could have asserted them. That is nice because I could go as far as I wanted to. I am undecided if I should test colours and other styling related things. As I said, there seems to be consensus to not assert on layout or styling and I did not. In general it is still unclear (for me) how much automated testing is needed for an UI in such situations. While I did not write tests for everything, I already have a feeling that there are "lots of test but no application".

20 January 2020

Login Form TDD a UI Kata

User interfaces are usually considered hard to test, and people rarely develop their user interfaces using Test Driven Development. So it is considered hard. I like hard and I like challenges. I started to research the topic last year. Actually I went crazy. Besides my own experiments and practice, I hijacked most Coding Dojo and Coderetreat sessions and tried to TDD user interfaces with my pairing partners. I discussed the topic at unconferences and spent dedicated time with people in learning workshops. Besides its use I just wanted to see how far I could go.

This is the first article in a series describing what I learned. I spent more than half a year of my learning time on this topic and tried different approaches. In the past I found myself a different topic to research each year. Previous topics included Scheme and Architectural Refactoring. Currently I am investigating Splitting the Monolith. This makes me leave my research kind of unfinished - probably it is impossible to "finish" learning at all. I want to collect what I have learned during last half year before diving into something else.

The Exercise
To experiment with Test Driven Development of user interfaces, we need some UI to build. What would be a small UI that most people know? A login dialogue. I created a repository to drive the UI of a Login Form using TDD, the Login Form TDD UI kata. Your task is to create a Login window or form or web page. Here are the requirements:

Existing Code Back End
The exercise is focused on the front end part. Let's just assume an Authentication service, facade or end point which will be simulated in the tests. It has a method authenticate() to authenticate a user based on her phone, email or user name and her password. The call returns an AuthenticationResult which indicates success and an optional message for error situations. From now on the combination of a user's phone, email or user name is called the user's lookup. Under certain conditions, the UI logic will invoke this service or back end. Calls to the back end might take some time and/or block, so these calls must done asynchronously to keep the user interface responsive.

Requirements for the Minimum Functionality
  • There is a user name input field, which is limited to 20 characters.
  • The label "Phone, email or username" is left, next to the input field.
  • There is a password field, which is limited to 20 characters.
  • The password is either visible as asterisk or bullet signs.
  • The label "Password" is left, next to the input field.
  • There is a "Log in" button in the bottom right corner of the window.
  • There is a label in a red box above the button. It is only visible if there was an error.
These requirements are just describing the UI. The more interesting part is the logic. The logic uses the Authentication back end described above.
  • When user name and password are given, button "Log in" is clicked and the back end reports success, then the form is closed.
  • When user name and password given, button "Log in" is clicked but the back end reports an error, a message in the error line is shown and the form stays open.
  • While the back end is working, the "Log in" button is disabled.
My friend Thomas said that UI requirements need wireframes. So here is a sketch. Pretty, isn't it? ;-)

Bare Login Form Sketch
More Requirements
The goal of the kata is to experiment with driving the UI using tests. Maybe you want to ignore the styling (most people do) or ignore the visual elements completely. Or maybe you want to focus specifically on styling. Clearly we need more requirements like
  • More functionality while the back end is working
  • More logic in the view itself when username or password is not given
  • More UI elements like titles and logos
  • Detailed styling of all elements
  • Focus and tab order
  • Checkbox to show password
  • Caps Lock Warning
All these requirements and even more are listed in detail in LoginDialogRequirements.md inside the kata repository. The task is progressive: If you want more logic then go for more logic, for more styling add more styling. Thanks to Nick Babich, Software Testing Help and Anton Angelov this will be the most complete login you will ever build. Here is the styled sketch of the final Login:

Login Form Sketch of Everything Styled
Drive the UI of a Login Form using TDD
I created this kata to explore test driving UIs: login-form-tdd-ui-kata. Currently it contains code to get started in the following languages and UI frameworks:
  • Java/Swing
  • Java/Vaadin
  • Kotlin/Android
  • Go/raylib-go
  • JavaScript/plain browser DOM
  • JavaScript/React
Give it a try! If you do, please commit after each TDD step and share your repository so I can analyse it. Have fun!

7 January 2020

Visualising Architecture: GraphML Charting Module Dependencies

When working with existing code, analysing module dependencies helps me understand the bigger picture. For well defined modules like Eclipse OSGi or Maven there are tools to show all modules and their inter dependencies, e.g. the Eclipse Dependency Visualization tool or the Maven Module Dependency Graph Creator. For legacy technologies like COBOL and NATURAL - and probably some more platforms - we struggle due to the lack of such tools. Then the best approach is to extract the necessary information and put it into a modern, well known format. I wrote about such an approach in the past, e.g. loading references from a CSV into Neo4j for easy navigation and visualization. Today I want to sketch another idea I have used since many years: Using GraphML to chart module dependencies. For example, the following graph shows the (filtered) modules of a NATURAL application together with their dependencies in an organic layout.

Some modules of a NATURAL application in an organic layout, 2017
Process
GraphML is an XML-based file format for graphs. [...] It uses an XML-based syntax and supports the entire range of possible graph structure constellations including directed, undirected, mixed graphs, hyper graphs, and application-specific attributes. That should be more than enough to visualize any module dependencies. In fact I just need nodes and edges. My process to use GraphML is always the same:
  1. Start with defining or extracting the modules and their dependencies.
  2. Create a little script which loads the extracted data and creates a raw GraphML XML file.
  3. Use an existing graph editor to tweak and layout the diagram.
  4. Export the the diagram as PDF or as image.
Get the raw data
Extracting the module information is highly programming language specific. For Java I used my JavaClass class file parser. For NATURAL I used a CSV of all references which was provided by my client. Usually regular expressions work well to parse import, using or include statements. For example to analyse plain C, scan for #include statements (as done in Schmidrules for Application Architecture. Unfortunately there is not much documentation available about Schmidrules, which I will fix in the future.)

Create the XML
The next task is to create the XML. I use a little Ruby script to serializes a graph of nodes into GraphML. The used Node class needs a name and a list of dependencies, which are Nodes again. save stores the graph as GraphML.
require 'rexml/document'

class GraphmlSerializer
  include REXML

  # Save the _graph_ to _filename_ .
  def save(filename, graph)
    File.open(filename + '.graphml', 'w') do |f|
      doc = graph_to_xml(graph)
      doc.write(out_string = '<?xml version="1.0" encoding="UTF-8" standalone="no"?>')
      f.print out_string
    end
  end

  # Return an XML document of the GraphML serialized _graph_ .
  def graph_to_xml(graph)
    doc = create_xml_doc
    container = add_graph_element(doc)
    graph.to_a.each { |node| add_node_as_xml(container, node) }
    doc
  end

  private

  def create_xml_doc
    REXML::Document.new
  end

  def add_graph_element(doc)
    root = doc.add_element('graphml',
      'xmlns' => 'http://graphml.graphdrawing.org/xmlns',
      'xmlns:y' => 'http://www.yworks.com/xml/graphml',
      'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
      'xsi:schemaLocation' => 'http://graphml.graphdrawing.org/xmlns http://www.yworks.com/xml/schema/graphml/1.1/ygraphml.xsd')
    root.add_element('key', 'id' => 'n1',
                     'for' => 'node',
                     'yfiles.type' => 'nodegraphics')
    root.add_element('key', 'id' => 'e1',
                     'for' => 'edge',
                     'yfiles.type' => 'edgegraphics')

    root.add_element('graph', 'edgedefault' => 'directed')
  end

  public

  # Add the _node_ as XML to the _container_ .
  def add_node_as_xml(container, node)
    add_node_element(container, node)

    node.dependencies.each do |dep|
      add_edge_element(container, node, dep)
    end
  end

  private

  def add_node_element(container, node)
    elem = container.add_element('node', 'id' => node.name)
    shape_node = elem.add_element('data', 'key' => 'n1').
      add_element('y:ShapeNode')
    shape_node.
      add_element('y:NodeLabel').
      add_text(node.to_s)
  end

  def add_edge_element(container, node, dep)
    edge = container.add_element('edge')
    edge.add_attribute('id', node.name + '.' + dep.name)
    edge.add_attribute('source', node.name)
    edge.add_attribute('target', dep.name)
  end

end
Layout the diagram
I do not try to layout the graph when creating it. Existing tools do a much better job. I use the yEd Graph Editor. yEd is a Java application. Download and uncompress the zipped archive. To get the final diagram
  1. I load the GraphML file into the editor. (If the graph is huge, yEd needs more memory. yEd is just an executable Jar - Java Archive - it can get more heap on startup using java -XX:+UseG1GC -Xmx800m -jar ./yed-3.16.2.1/yed.jar.)
  2. Then I select all nodes and apply menu commands Tools/Fit Node to Label. This is because the size of the nodes does not match the size of the node's names.
  3. Finally I apply the menu commands Layout/Hierarchical or maybe Layout/Organic/Smart. In the end it needs some trial and error to find the proper layout.
Conclusion
This approach is very flexible. The nodes of the graph can be anything, a "module" can be a file, a folder or a bunch of folders. In the example shown above, the nodes where NATURAL modules (aka files), i.e. functions, subroutines, programs or includes. In another example shipped with JavaClass the nodes are components, i.e. source folders similar to Maven multi module projects. The diagram below shows the components of a product family of large Eclipse RCP applications with their dependencies in a hierarchical layout. Pretty crazy, isn't it. ;-)

Components of an Eclipse RCP application in hierarchical layout, 2012