Test your class for compareTo()

Một phần của tài liệu Manning JUnit recipes practical methods for program (Trang 618 - 621)

Problem

You want to verify your implementation of the Comparable interface without writ- ing custom tests for each Comparable class you have.

Background

Any class that you store in a sorted collection (SortedSet, SortedList, the keys in a SortedMap) needs to implement java.lang.Comparable; otherwise, the collection cannot know how to keep the objects in sorted order. The behavior of Compara- ble.compareTo() can be checked with a “universal compareTo() test,” much the way we have described testing your implementation of equals() in recipe 2.1, “Test your equals method.” Because a domain model might have dozens of Comparable classes, it would be nice to have one way of ensuring that they all implement Compa- rable correctly.

Recipe

JUnit-addons provides junitx.extensions.ComparabilityTestCase to provide the framework for testing your Comparable classes. It defines the tests your class needs to pass and you provide the test data through an Abstract Test Case design (see recipe 2.6, “Test an interface” for a discussion of the Abstract Test Case pattern).

Listing 16.1 shows the “abstract” part of this universal comparability test.

public abstract class ComparabilityTestCase extends TestCase {

protected abstract Comparable createLessInstance() throws Exception;

protected abstract Comparable createEqualInstance() throws Exception;

Listing 16.1 ComparabilityTestCase (abstract methods)

588 CHAPTER 16 JUnit-addons

protected abstract Comparable createGreaterInstance() throws Exception;

}

To use this comparability test, create a subclass of ComparabilityTestCase and then implement the required methods to return objects that you expect to be ordered as follows: lessInstance, which is less than equalInstance, which is less than greaterInstance.

Each invocation of these methods must return a new object. The Abstract Test Case class provides all the tests: it verifies that the class under test respects the con- tract of Comparable. Listing 16.2 shows one of the tests it provides.

public abstract class ComparabilityTestCase extends TestCase {

public final void testReturnValues() {

ComparableAssert.assertLesser(equal1, less);

ComparableAssert.assertLesser(equal2, less);

ComparableAssert.assertGreater(less, greater);

ComparableAssert.assertEquals(equal1, equal2);

ComparableAssert.assertGreater(equal1, greater);

ComparableAssert.assertGreater(equal2, greater);

} }

Perhaps these assertions are a little confusing. They were to us, at first. Note that in each one, the expected (or limit) value is the first parameter and the actual value is the second. To read these assertions we have to work backwards, in a sense. For example, read the first assertion as “less (the actual value) should be less than equal1 (the limit value),” even though this goes against the common-sense con- vention of reading parameters from left to right. Vladimir is simply using the same coding convention as JUnit’s assertEquals(), where the value we are com- paring is on the right, but the expected (or limit) value against which to compare is on the left.

This test checks various pairs of objects for the appropriate lesser than, equal to, or greater than relationship. Notice that it does not verify whether compareTo() is consistent with equals(). It is common for the two methods to be consistent, but it is not strictly necessary. To be consistent, compareTo() would have to return 0 when comparing objects that are equal according to equals(). If you need to

Listing 16.2 A test from ComparabilityTestCase

589 Test your class for compareTo()

verify this additional constraint, then continue to the Discussion section of this recipe. Listing 16.3 contains a sample comparability test, verifying String compar- isons. Notice that the “create” methods return a new String each time, as the Com- parabilityTestCase documentation indicates is needed.

package junit.cookbook.addons.test;

import junitx.extensions.ComparabilityTestCase;

public class StringCompareToTest extends ComparabilityTestCase { public StringCompareToTest(String name) {

super(name);

}

protected Comparable createLessInstance() throws Exception { return new String("abc");

}

protected Comparable createEqualInstance() throws Exception { return new String("abcd");

}

protected Comparable createGreaterInstance() throws Exception { return new String("abcde");

} }

Discussion

ComparabilityTestCase uses custom assertion methods from ComparableAssert, also part of JUnit-addons (see recipe 17.4, “Extract a custom assertion”). These custom assertion methods provide a uniform, informative failure message that looks quite a bit like the failure message for JUnit’s own assertEquals().

If you need to further verify that compareTo() is consistent with equals(), you need to add another test.

public void testConsistentWithEquals() throws Exception { assertEquals(

"compareTo() is inconsistent with equals", 0,

createEqualInstance().compareTo(createEqualInstance()));

}

Perhaps by the time you read this, someone will have submitted this as a patch to JUnit-addons.

Listing 16.3 Comparability test for class String

590 CHAPTER 16 JUnit-addons

Related

■ 2.1—Test your equals method

■ 2.6—Test an interface

■ 17.4—Extract a custom assertion

Một phần của tài liệu Manning JUnit recipes practical methods for program (Trang 618 - 621)

Tải bản đầy đủ (PDF)

(753 trang)