CS494: In-lab Exercise
Wednesday, April 20

Design Recovery

Give your name to the TA in the lab so we know you were here in lab today and worked through these exercises!

Get a copy of the JUnit project's source files. (For a reminder of how to import these into Eclipse, see this earlier exercise.) For the purposes of this lab, you might want create a copy of your project. (In the Package Explore, right-click and choose Copy. Then right-click, choose Paste, and give your copy a sensible name in the dialog that appears.)


1. Package Relationships

Create a package dependency diagram for JUnit:

What if we want to know the relationship between the extensions package and the rest of JUnit? There are several ways to explore this using the tools we have. Try each of the methods below to see which helps you answer these two questions (which are very practical things to ask about a large system).
(1) What if you wanted to find out what other classes might import classes from the extensions diagrams?
(2) Can you tell what classes are used by classes in the extensions package?

Explain to the TA or the instructor what your experiences were with these three approaches.


2. Class Diagrams

Create class diagram for the framework package:

Explore how you can use the results class diagram.

Layout of the class diagram with a lot of classes is clearly not ideal, but for smaller sets of packages (e.g. java.awtui) it is useful "as is" and probably can be made more useful if one took the time to clean up the diagrams it generated.


3. Sequence Diagrams

Let's see if sequence diagrams can help us explore how the Observer design pattern is used in JUnit. Keep in mind that:

The class TestResult has the role of subject (or observable). A TestResult object changes when someone (itself, perhaps) calls either addFailure() or addError() on that object. (JUnit has two types of failed results.)

Let's create a sequence diagram for this call. Click on the method TestResult.addError() in any view, and then right-click. Under Open UML, choose the sequence diagram operation. Again, you have the Outline view to the right, you can maximize the diagram window, and you can also change the scale of the diagram from 100% to some other scale value in a toolbar at the top.

We'd expect TestResult.addError() to call an "update" operation on each observer object in its collection of observers. In this diagram, can you see the object (and its type) of the observer and what the name of that "update" operation is? Why don't we see the "real" type in this diagram? Discuss with your partner or the TA.


4. Execution of a Test-Class

The observer design pattern you just explored plays a role in the overall execution structure of JUnit. Let's explore how this works by starting with one of the three versions of a test "runner" class.

In the package textui there's a TestRunner that provides a command-line based tool to run tests. When it runs, it's given the name of one test-class to be run. (By the way, there are runners for each of the three UI packages. This one is the simplest to look at, but feel free to explore the swing version.)

Choose the TestRunner.doRun(Test,boolean) method, and create a sequence diagram. From this, can you see what the four major steps are that take place in this method?

Do you think that a TestRunner object might be acting as an observer of a TestResult? If so, what do you see in this diagram that tells you this?

Explain precisely what it is about how TestRunner is defined as a class that makes it an observer type. You might not see it right away in the code. You may find the Type Hierarchy view useful. (Remember, click on a type anywhere and hit F4.)

List all the concrete classes in junit that can be an observer of a TestResult.


5. Wrap Up

Discuss what's good and bad, what you like and don't like, about using Omondo's UML product for reverse engineering to learn about the design of a system like JUnit.