Section 35.2. Testing Indirectly


35.2. Testing Indirectly

Another approach is to carry out, through the API, actions that emulate the user's actions. This approach has the advantage of checking that the calculation business rules are handled in the workflow. This may be the only way if the corresponding logic is awkwardly embedded and if test support is needed to untangle it in order to later test it directly.

Part of the test from Chapter 16 is shown in Figure 35.2. (The fixture name in the initial table is altered, however, so that it can make use of the fixtures that were developed for other Fit tests in the past few chapters.)

Figure 35.2. Testing Through the Application


The action in the first row of the second table results in a call of the method refundDollarPerHourPerDayPerWeek() of the StartApplication object, as shown in Listing 35.3. This creates temporary client and staff objects; makeDummyClient() in Listing 35.3, for example, is used by a variety of such tests. This method also creates a rental item object with the appropriate charge rates to use. It returns a Refunder CalculateFixture object, which is used for the rest of the table rows.

The CalculateFixture class Refunder is shown in Listing 35.4. For each row of the second table, from the third row on, the method refundPaidTimeActualTime() is called with two Durations.

The refundPaidTimeActualTime() method makes use of TRansActionFixture methods to carry out the operations, rather than duplicating code. The method creates a start date and an end date, with the given duration between them. With the first transaction, created with the start dateequivalent to the action time is nowit rents an item until the end date, pays the cost, and completes the transaction.

Listing 35.3. StartApplication.java
 public class StartApplication extends DoFixture {    private RentEz rentEz;    public Fixture refundDollarPerHourPerDayPerWeek(Money perHour,           Money perDay, Money perWeek) throws Exception {       StaffMember staff = makeDummyStaff();       Client client = makeDummyClient();       RentalItemType item = makeDummyRentalItem(              new Rates(perHour, perDay, perWeek));       return new Refunder(rentEz,staff,client,item.getName());    }    private RentalItemType makeDummyRentalItem(Rates rates) {       final String name = "dummy-rental";       final int count = 1;       final Money bond = new Money(0);       rentEz.removeRentalItemType(name);       rentEz.createRentalItemType(name,count,rates,bond);       return rentEz.getRentalItemType(name);    }    private Client makeDummyClient() throws RpsException {       final String name = "dummy-client";       try {          return getClient(name);       } catch (MissingException e) {          rentEz.createClient(rentEz.getAdminStaff(), name, "phone");          return getClient(name);       }    }    // ... } 

The second transaction is created with a date corresponding to the end of the actual duration. Then the rental item is returned, the refund is made, and the transaction is completed. The method returns the refund amount.

Questions & Answers

Q1:

Why not simply run the whole application?

A1:

At this stage of revision, there are time overheads in running tests on the application, because of the need to set up the database data anew at the start of each test. We introduced this and related issues in Chapter 33.

Listing 35.4. Refunder.java
 public class Refunder extends CalculateFixture {    private RentEz rentEz;    private StaffMember staff;    private Client client;    private String rentalItemName;    public Refunder(RentEz rentEz, StaffMember staff,           Client client, String rentalItemName) {       this.rentEz = rentEz;       this.staff = staff;       this.client = client;       this.rentalItemName = rentalItemName;    }    public Money refundPaidTimeActualTime(Duration paidDuration,           Duration actual) {       final int count = 1;       final Date startDate = new Date();       final Date endDate = paidDuration.dateAfter(startDate);       // Use a transaction to rent the item for the period       TransActionFixture transAction = new TransActionFixture(rentEz,              new ClientTransaction(rentEz,startDate,staff,client));       Money cost = transAction.rentFor(count,rentalItemName,paidDuration);       transAction.payWithCashDollar(cost);       transAction.completeTransaction();       // Use a transaction to return the item after the required delay       TransActionFixture finalTransAction = new TransActionFixture(rentEz,              new ClientTransaction(rentEz,endDate,staff,client));       Money refund = finalTransAction.returnItems(count,rentalItemName);       finalTransAction.refundCashDollar(refund);       finalTransAction.completeTransaction();       return refund;    } } 

Q2:

Isn't there a potential problem if the RentEz object is reused for each test row here?

A2:

Yes. If the state of the RentEz object is not restored after each test, it will affect the next one. However, it takes time to restart the system under test each time, so it's good to avoid this.

Given that this is the responsibility of the fixture code in Refunder, rather than the Fit tests themselves, it seems like a reasonable compromise. If we decided to change the fixture so a new system under test was used for each test row, it wouldn't make any difference to the Fit tables.



    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