Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
JUnit In Action.pdf
Скачиваний:
15
Добавлен:
20.05.2015
Размер:
16.4 Mб
Скачать

Collecting parameters with TestResult

25

 

 

In chapter 5, we look at several techniques for automating tasks like this one, so that you do not have to create and maintain a TestAll class. Of course, you still may want to create specialty suites for discrete subsets of your tests.

Design patterns in action: Composite and Command

Composite pattern. “Compose objects into tree structures to represent partwhole hierarchies. Composite lets clients treat individual objects and compositions of objects uniformly.”1 JUnit’s use of the Test interface to run a single test or suites of suites of suites of tests is an example of the Composite pattern. When you add an object to a TestSuite, you are really adding a Test, not simply a TestCase. Because both TestSuite and TestCase implement Test, you can add either to a suite. If the Test is a TestCase, the single test is run. If the Test is a TestSuite, then a group of tests is run (which could include other TestSuites).

Command pattern. “Encapsulate a request as an object, thereby letting you parameterize clients with different requests, queue or log requests, and support undoable operations.”2 The use of the Test interface to provide a common run method is an example of the Command pattern.

2.4 Collecting parameters with TestResult

Newton taught us that for every action there is an equal and opposite reaction. Likewise, for every TestSuite, there is a TestResult.

A TestResult collects the results of executing a TestCase. If all your tests always succeeded, what would be the point of running them? So, TestResult stores the details of all your tests, pass or fail.

The TestCalculator program (listing 2.1) includes a line that says

assertEquals(60, result, 0);

If the result did not equal 60, JUnit would create a TestFailure object to be stored in the TestResult.

The TestRunner uses the TestResult to report the outcome of your tests. If there are no TestFailures in the TestResult collection, then the code is clean, and the bar turns green. If there are failures, the TestRunner reports the failure

1Erich Gamma et al., Design Patterns (Reading, MA: Addison-Wesley, 1995).

2Ibid.

26CHAPTER 2

Exploring JUnit

count and the stack trace for failing tests. Figure 2.4 shows what a failed test looks like in the Swing test runner.

JUnit distinguishes between failures and errors. Failures are to be expected. From time to time changes in the code will cause an assertion to fail. When it does, you fix the code so the failure goes away. An error is an unexpected condition that is not expected by the test, such as an exception in a conventional program.

Of course, an error may indicate a failure in the underlying environment. The test itself may not be broken. A good heuristic in the face of an error is the following:

Check the environment. (Is the database up? What about the network?)

Check the test.

Check the code.

Figure 2.5 shows what an error condition looks like in the Swing test runner. At the end of a suite, the test runner provides a tally of how many tests passed and failed, along with details of any test that failed.

With JUnit 3.8.1, you can use the automatic suite mechanism to ensure that any new tests you write are included in the run. If you’d like to retain the results

Figure 2.4 Oops—time to fix the code!

Observing results with TestListener

27

 

 

Figure 2.5

Oh, no! You have to fix the test!

for later review, you can do so using Ant, Eclipse, and other tools. See chapter 5 for more about using automated tools.

The TestResult is used by almost all the JUnit classes internally. As a JUnit test writer, you won’t interact with the TestResult directly; but in trying to understand how JUnit works, it’s helpful to know that it exists.

Design patterns in action: Collecting Parameter

“When you need to collect results over several methods, you should add a parameter to the method and pass an object that will collect the results for you.”3 The TestResult class is an example of the Collecting Parameter pattern.

2.5 Observing results with TestListener

The TestResult collects information about the test, and the TestRunner reports it. But does an object have to be a TestRunner to report on a test? Can more than one object report on a test at once?

The JUnit framework provides the TestListener interface to help objects access the TestResult and create useful reports. The TestRunners implement TestListener, as do many of the special JUnit extensions. Any number of TestListeners can register with the framework and do whatever they need to do

3 Kent Beck, Smalltalk Best Practice Patterns (Upper Saddle River, NJ: Prentice Hall, 1996).

28CHAPTER 2

Exploring JUnit

with the information provided by the TestResult. Table 2.2 describes the

TestListener interface.

NOTE Although the TestListener interface is an essential part of the JUnit framework, it is not an interface that you will implement when writing your own tests. We provide this section for completeness only.

Table 2.2 The TestListener interface

 

Method

Description

 

 

void addError(Test test, Throwable t)

Called when an error occurs

 

 

void addFailure(Test test, AssertionFailedError e)

Called when a failure occurs

 

 

 

void

endTest(Test test)

Called when a test ends

 

 

 

void

startTest(Test test)

Called when a test begins

 

 

 

As mentioned, although the TestListener interface is an interesting bit of plumbing, you would only need to implement it if you were extending the JUnit framework, rather than just using it.

Design patterns in action: Observer

“Define a one-to-many dependency between objects so that when one object changes state, all its dependants are notified and updated automatically.”4

The TestRunner registering as a TestListener with the TestResult is an example of the Observer pattern.

2.6 Working with TestCase

The JUnit big picture is that the TestRunner runs a TestSuite, which contains one or more TestCases (or other TestSuites). On a daily basis, you usually work only with the TestCases.

The framework ships with ready-to-use graphical and textual TestRunners. The framework can also generate a default runtime TestSuite for you. So, the only class you absolutely must provide yourself is the TestCase. A typical TestCase includes two major components: the fixture and the unit tests.

4 Ibid.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]