The Artima Developer Community
Sponsored Link

Artima SuiteRunner Tutorial
Building Conformance and Unit Tests with Artima SuiteRunner
by Bill Venners
February 10, 2003

<<  Page 4 of 8  >>

Advertisement

Writing Test Methods

Test methods may have one of two signatures:

The "..." in "test..." represents any non-zero length string. Some example test method names are testFest, testimonial, and testOfCharacter.

Test methods indicate success by returning, failure by throwing an exception. The Artima SuiteRunner API includes one exception, TestFailedException, whose purpose is to indicate a failed test. Suite.executeTestMethods interprets any exception thrown from a test method, not just TestFailedException, as an indication of failure.

In the body of test methods, you can take advantage of these six methods declared in superclass Suite:

The verify methods check the specified Boolean condition. If the condition is true, verify returns quietly. Else, verify throws TestFailedException. The verify method that takes a String message parameter uses that String for the detail message of the thrown exception.

The fail methods always throw TestFailedException. If a String message or Throwable cause is provided, the fail method uses these as the detail message and cause for the thrown TestFailedException.

Test methods generally do not catch TestFailedException. Instead, they complete abruptly with the exception, thereby indicating failure. The calling method, usually Suite.executeTestMethods, catches the exception and reports the failure to the Reporter. The Reporter in turn passes the information in some manner along to the user.

As an example, here's the testDeposit method of class AccountSuite from the account example:

public void testDeposit() {

    Account account = new Account();

    account.deposit(20);
    long bal = account.getBalance();
    verify(bal == 20,  "Account.deposit() didn't deposit 20 correctly. "
            + "Resulting balance should have been 20, but was " + bal + ".");

    account.deposit(20);
    bal = account.getBalance();
    verify(bal == 40,  "Account.deposit() didn't deposit 20 twice correctly. "
            + "Resulting balance should have been 40, but was " + bal + ".");

    try {
        account.deposit(-1); 
        fail("Account.deposit() didn't throw IllegalArgumentException when "
            + "negative value passed");
    }
    catch (IllegalArgumentException e) {
        // This is supposed to happen, so just keep going
    }

    account = new Account();
    account.deposit(Long.MAX_VALUE);
    verify(account.getBalance() == Long.MAX_VALUE, "account.deposit() "
            + "couldn't handle Long.MAX_VALUE");

    account = new Account();
    account.deposit(1);
    try {
        account.deposit(Long.MAX_VALUE);
        fail("Account.deposit() didn't throw ArithmenticException when a "
            + "value passed that would cause overflow");
    }
    catch (ArithmeticException e) {
        // This is supposed to happen, so just keep going
    }
}

Inside the testDeposit method, I call deposit (the target of this test method) several times on various Account objects, making sure it either performs the correct action or throws the expected exception. For example, after you deposit 20 into an Account, that Account's getBalance method should return 20. The first verify statement in the method checks to make sure that getBalance returns the expected value of 20:

    account.deposit(20);
    long bal = account.getBalance();
    verify(bal == 20,  "Account.deposit() didn't deposit 20 correctly. "
            + "Resulting balance should have been 20, but was " + bal + ".");

In addition, the contract of Account.deposit states that the method should throw IllegalArgumentException if the requested deposit is less than or equal to zero. The following code ensures this behavior works according to the contract:

    try {
        account.deposit(-1);     
        fail("Account.deposit() didn't throw IllegalArgumentException when "
            + "negative value passed");
    }
    catch (IllegalArgumentException e) {
        // This is supposed to happen, so just keep going
    }

The previous code snippet shows one use of the fail method. If account.deposit(-1) throws IllegalArgumentException as expected, it will be caught by the empty catch clause and the test method will continue. But if account.deposit(-1) returns normally, instead of throwing a IllegalArgumentException as required, the fail method will be invoked resulting in a TestFailedException. If account.deposit(-1) throws a different exception besides IllegalArgumentException, then the entire testDeposit method will complete abruptly with that exception. The calling method (normally executeTestMethods) will catch any exception and report the failure to the Reporter.

Artima SuiteRunner's TestFailedException corresponds to JUnit's AssertionFailedError. Artima SuiteRunner's two verify methods correspond to the JUnit's multitudinous assert methods declared in class Assert. Unlike JUnit, Artima SuiteRunner does not differentiate between "failures" and "errors." JUnit calls any thrown AssertionFailedError a failure, any other thrown exception an error. In Artima SuiteRunner, a test either succeeds or fails. If the test fails, the user can inspect information about the failure to better understand how to correct the problem.

<<  Page 4 of 8  >>


Sponsored Links



Google
  Web Artima.com   
Copyright © 1996-2017 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use - Advertise with Us