Section 25.2. Values of Money


25.2. Values of Money

We will now look in detail at how values of Money can be used in Fit tables. In the process, we will show how the fixture needs to deal with the conversion and comparison issues as discussed in the previous section. Specifically, we need to specify how String values will be converted to objects of that type, and vice versa, and how two values of that type will be checked to see whether they are equal.

Consider the altered discount tests shown in Figure 25.1. Here, we require that the money values be shown with a leading $ and exactly two decimal places of precision.

Figure 25.1. Revised Table for Testing Discount

CalculateDiscountMoney

amount

discount()

$999.99

$0.00

$1000.00

$0.00

$1000.01

$50.00

$1001.33

$50.07

$1010.00

$50.50

$1100.00

$55.00

$1200.00

$60.00

$2000.00

$100.00


The fixture code for this is the class TestDiscount, as shown in Listing 25.1. The public instance variable amount is of type Money, which Fit does not handle automatically.

To handle conversion from the textual form of the value to a corresponding objecthere, of Moneythe fixture defines the method parse(). This method overrides the default method in class Fixture to specify how to convert a textual value, from a table cell, into an object of the right class. This method is called whenever a TypeAdapter is needed by a fixture, such as when a ColumnFixture is processing the labels in the header of the table.

The parse() method in class TestDiscount, as shown in Listing 25.1, checks whether the type is Money. If so, the method calls the static method parse() of class Money. Otherwise, the superclass method is called to handle it.

Listing 25.1. TestDiscount.java
 public class TestDiscount extends fit.ColumnFixture {    public Money amount;    private Discount application = new Discount();    public Money discount() {       return application.discount(amount);    }    public Object parse(String s, Class type) throws Exception {       if (type == Money.class)          return Money.parse(s);       return super.parse(s, type);    } } 

As Fit needs to report unexpected values, a String value from our Money object is needed. The standard method toString(), as defined in class Object, is used for this purpose.

As Fit fixtures need to make comparisons, we need a way to test whether the expected and actual values, or objects, are the same. Fit relies on the standard method equals() to do this.

The relevant part of our application class Money is shown in Listing 25.2. The static method parse() takes a String and converts it to an object of Money. The method toString() provides a String value. The equals() method checks whether two Money objects are the same; it is called by Fit with the expected and actual values after they have been converted to objects.

Listing 25.2. Money.java
 public class Money {    private long cents;    public Money(long cents) {       this.cents = cents;    }    public boolean equals(Object other) {       return other instanceof Money &&          ((Money)other).cents == cents;    }    public int hashCode() {       return (int)cents;    }    public String toString() {       String centString = ""+cents%100;       if (centString.length() == 1)           centString += "0";       return "$"+cents/100+"."+centString;    }    public static Money parse(String s) {       if (s.charAt(0) != "$")          throw new RuntimeException("Invalid money");       int dot = s.indexOf(".");       if (dot < 0 || dot != s.length() - 3)          throw new RuntimeException("Invalid money");       String scent = s.substring(1);       double amount = Double.valueOf(scent).doubleValue()*100;       return new Money((long)amount);    }    // ... } 

Questions & Answers

Q1:

Where does parse() go with an ActionFixture?

A1:

It goes in the actor class. That's why actors have to be Fixtures.

Q2:

What about with standard Java classes, such as Point?

A2:

The same approach applies; you override the parse() of the fixture concerned to specify the text-to-object conversion. An example of formatting Date in a specialized way is provided in Section 34.4 on p. 292.

It's likely that the class will have suitable toString() and equals() methods. If not, you'd need to wrap them up in another object that provides the behavior you require. This is a way, for example, to make comparisons case insensitive.

Q3:

What if many fixtures need to use our own classes? Won't there be lots of duplication?

A3:

In that case, use the subclassing approach to eliminate unnecessary duplication. Define your own ColumnFixture and RowFixture subclasses that include the needed parse() method. Then create subclasses of those classes for your specific fixtures.

For ActionFixture, define your own subclass of Fixture with the needed parse() method, and make all your actor classes subclass that class.

Q4:

Isn't there a better way?

A4:

See the next section.



    Fit for Developing Software. Framework for Integrated Tests
    Fit for Developing Software: Framework for Integrated Tests
    ISBN: 0321269349
    EAN: 2147483647
    Year: 2005
    Pages: 331

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