Chapter 5: The Inner Life of a Test Framework


As mere users of a test framework, we should not bother about its internal structure, unless we are programmers and, as such, interested in the inner parts of each piece of software we can get a hold of. In addition, unit testing is such an individual activity that we may sometimes not get around expansions and adaptations of the framework. JUnit does not cover every functionality anyone may need during testing; it is an open core that can be expanded and completed in different places. And if we find that JUnit limits our own test needs too much, then it may still serve us as an example for the benefits and drawbacks of certain design decisions in the development of our own test support tools.

5.1 Statics

So far, we have introduced three classes: TestRunner (in three different variants), TestCase, and TestSuite. But JUnit has much more in store. The inner structure of JUnit—mainly the package junit.framework—is a small tutorial in itself for the use of a large number of design patterns [Gamma95]. Kent Beck and Erich Gamma [Beck99] describe the patterns used and their motivation. [1] The article and the accompanying study of the JUnit sources is recommended to everyone and is an absolute must for all who want to understand and expand JUnit, even though JUnit has been further developed in the interim.

Figure 5.1 shows a small section from the inner life of JUnit Version 3.8. Except for TestDecorator, this class diagram shows a section from the junit.framework package. What is new for us are the "extension hooks" for project-specific and functional expansions of the JUnit framework:

  • TestResult is the container of all results from a test run. All classes implementing the test interface—TestCase, TestSuite, and TestDecorator—become an instance of the class TestResult in its run() method.

  • A TestListener can be registered with a TestResult by using addListener() to obtain information about start, end, failure, and error events in a test. This possibility is used by all of the three TestRunner classes to get notification about the current state of a test run.

    The class TestDecorator serves as a superclass for a large number of expansions of the test framework. As the name implies, it implements the decorator pattern described by Gamma et al. [95], allowing the use of several concurrent expansions. Practical examples are included in the junit.extensions package.

    Most JUnit expansions are developed as subclasses of TestCase. If we use TestDecorator instead, then we have the benefit that several expansions can be used concurrently. The drawback is that the application becomes more complex, because a decorator instance has to be added explicitly to a test or test suite.

  • AssertionFailedError is an exception thrown when an assert call fails, is caught by TestCase instances, and finally passed on to a TestResult for registration.

  • Assert is a superclass of TestCase and accommodates all variants of the assert method, all of which are also static. In this way, other classes, like test decorators, can also use the assert functionality. The extent of the assert variants available and their implementations is the focus of constant discussion in the JUnit discussion group [URL:YahooJUnit]. Project-specific expansions normally include a new assert method in one form or another to compare certain collection classes or other data structures.

click to expand
Figure 5.1: JUnit class diagram.

Knowing how JUnit is built inside is very useful, especially when you decide to start peeking behind the TestCase scene to enjoy some well written source text of the framework.

[1]This article is included in the JUnit documentation as cookstour.htm.




Unit Testing in Java. How Tests Drive the Code
Unit Testing in Java: How Tests Drive the Code (The Morgan Kaufmann Series in Software Engineering and Programming)
ISBN: 1558608680
EAN: 2147483647
Year: 2003
Pages: 144
Authors: Johannes Link

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net