Example: Stubs |
Examples of stubs for different circumstances.
Relationships
Related Elements | Developer Testing Stubs
Description
Main Description | Unless the stubs were constructed because the real component wasn't available yet, you should expect to retain them past deployment. The tests they support will likely be important during product maintenance. Stubs, therefore, need to be written to higher standards than throwaway code. While they don't need to meet the standards of product code - for example, most do not need a test suite of their own - later developers will have to maintain them as components of the product change. If that maintenance is too hard, the stubs will be discarded, and the investment in them will be lost. Especially when they're to be retained, stubs alter component design. For example, suppose your component will use a database to store key/value pairs persistently. Consider two design scenarios: Scenario 1: The database is used for testing as well as for normal use. The existence of the database needn't be hidden from the component. You might initialize it with the name of the database:
    public Component(

    String databaseURL)
    {
    try
    {
    databaseConnection = DriverManager.getConnection(databaseURL);
    ...
    } catch (SQLException e) {...}
    }
And, while you wouldn't want each location that read or wrote a value to construct a SQL statement, you'd certainly have some methods that contain SQL. For example, component code that needs a value might call this component method:
    public String get(String key)
    {
    try
    {
    Statement stmt = databaseConnection.createStatement();
    ResultSet rs = stmt.executeQuery(

    "SELECT value FROM Table1 WHERE key=" + key);
    ...
    } catch (SQLException e) {...}
    }
Scenario 2: For testing, the database is replaced by a stub. The component code should look the same whether it's running against the real database or the stub. So it needs to be coded to use methods of an abstract interface:
    interface KeyValuePairs
    {
    String

    get(String key);
    void

    put(String key, String value);
    }
Tests would implement KeyValuePairs with something simple like a hash table:
    class FakeDatabase implements KeyValuePairs
    {
    Hashtable table = new Hashtable();
    public String

    get(String key) {return (String) table.get(key); }
    public void

    put(String key, String value) {table.put(key, value); }
    }
When it is not being used in a test, the component would use an adapter object that converted calls to the KeyValuePairs interface into SQL statements:
    class DatabaseAdapter implements KeyValuePairs
    {
    private Connection databaseConnection;
    public DatabaseAdapter(String databaseURL)
    {
    try
    {
    databaseConnection = DriverManager.getConnection(databaseURL);
    ...
    } catch (SQLException e) {...}
    }
    public String

    get(String key)
    {
    try
    {
    Statement stmt = databaseConnection.createStatement();
    ResultSet rs = stmt.executeQuery("SELECT value FROM Table1 WHERE key=" + key);
    ...
    } catch (SQLException e) {...}
    }
    public void

    put(String key, String value) {... }
    }
Your component might have a single constructor for both tests and other clients. That constructor would take an object that implements KeyValuePairs. Or it might provide that interface only for tests, requiring that ordinary clients of the component pass in the name of a database:
    class Component
    {

    public Component(String databaseURL)
    {
    this.valueStash = new DatabaseAdapter(databaseURL);
    } // For testing.

    protected
    Component(KeyValuePairs valueStash)
    {
    this.valueStash = valueStash;
    }
    }
So, from the point of view of client programmers, the two design scenarios yield the same API, but one is more readily testable. (Some tests might use the real database and some might use the stub database.)
More Information
Concepts | Stubs
© Copyright IBM Corp. 1987, 2009. All Rights Reserved.