The Domain Layer

This tutorial assumes you’ve followed the prior tutorial, and have a Domain Layer (and tests to go along with it) as follows:

The Presentation Layer: Java Swing

Now you need a Java swing UI to allow the end user to interface with the Student Manager. Since we’re following TDD, that means we start by writing a test case.

So we’re going to add a class StudentManagerWindow to our class diagram; it will extend class javax.swing.JFrame.

From this point in the "assignment 1 preparation" tutorials, I’m not going to update the Class Diagram; I’m going to focus on how to test swing classes, and how to write swing applications using TDD.

Implementation

Write a Test

So how do you write tests for a JFrame?

JUnit: setUp and tearDown

Writing tests for GUIs is more challenging, so before we continue you’ll need to be familiar with JUnit’s setUp and tearDown methods. If you a Test Case implements these methods, they will be called between every test method. For example, running the following as a JUnit test:

Write Implementation

So you’ve got a test case, and now you need to implement your class StudentManagerWindow, which won’t be difficult with those super-nifty Eclipse quick-fix light bulbs! The resulting class should look something like this:

Write a Test – Does the JFrame Display the Students?

We want the StudentManagerWindow to include some sort of visual representation of the student repository, and we want it to be visible. In the interest of being able to test that functionality, we have a javax.swing.JTable, students, declared in class StudentManagerWindow, allowing to test it as follows:

Now your implementation matches the class diagram, but your test still doesn’t pass. The test is asserting whether students isShowing() so we need to add it to our StudentManagerWindow. We’ll do this in a constructor:

Write a Test – Is the "Add Student" Button Showing?

So now we have to write another test. We’re going to test whether or not the widgets necessary to add a student are available in our UI. We can do this by naming our components, and calling getComponents():

A much better idea would be to write a custom JPanel class which contains accessors to get the JButton and the JTextField (see below). When this tutorial was first written the plan was for this named-component method to be mental stepping stone to using getElementById calls with HTMLUnit testing – but that idea was scrapped.

… but I’m going to stick with the first implementation, which uses getName(), though you should strongly consider writing your own JPanel.

Write Implementation

In order to pass this test, our StudentManagerWindow has to contain a JPanel with a name of "add-student", which in turn must contain a JButton and a JTextField with names "add-student" and "add-student:student-id", respectively.

Write a Test – Does our JTable Display a List of Students?

Now we want to test that our JTable is hooked up to our StudentRepository. In order to do this, we’re going to write a custom implementation of class javax.swing.table.AbstractTableModel… but first, we write our test.

Have the StudentRepository update/refresh the JTable

So we need StudentRepository – on the low end of our Domain Layer – to update our JTable or the StudentManagerTableModel, both of which are distinctly in our Presentation Layer, and we don’t want to introduce an upwards dependancy, or any coupling between StudentRepository and javax.swing.* classes. If the Gang of Four authors were here, maybe they’d say that we need to…

Define a one-to-many dependancy between objects so that when one object changes state, all its dependancies are notified and updated automatically.

Which is the definition of the observer pattern.

Pattern: Observer

So let’s take a look at Observer: in observer we have 3(ish) participants:

ul >

The Subject, who changes state (in this case, the StudentRepository)

The Observer, an interface which de-couples the subject from the concrete observer

The Concrete Observer, who is notified (in this case the StudentManagerTableModel)

I won’t explicitly implement the observer pattern, but I will give a more final-ish Class Diagram:

Click to enlarge

… and the implementation of StudentManagerTableModel.update():

public void update() { // we can't call if notify(),
// notify() is a method of class Object
this.fireTableDataChanged();
}