Section 4.5. Running a Test with EasyMock

team bbl


4.5. Running a Test with EasyMock

It's time to run a test case. Since you're testing a JDBC application, it makes sense for us to verify that it's been used correctly.

Let's say that you wanted to test a single turn signal, one time. One way would be to stand behind the car, and then have someone inside activate the signal. If it didn't blink, then you'd say so. But say that you wanted to test the device before you put it into a car. One strategy would be to plug in a volt meter, a device that measures electricity, instead of a light bulb. Then, if the signal did not generate the right amount of electricity at the right time, the test would fail.

That's how a mock object works. Sometimes, instead of simulating the real world (like our stub in Chapter 1 that simulated a database), you want to know how your object under test is using its interfaces. You might use a mock object instead of a JDBC interface to make sure that the application opens the connection and closes it, just as you expect.

4.5.1. How do I do that?

You'll first need to install EasyMock. Download the latest version from http://www.easymock.org and place the easymock.jar file in your project's classpath. We've added it to our /lib folder.

Next, you can establish the collection of mock objects you'll need (Example 4-13). You are effectively drilling down through the JDBC interfaces, and it turns out you will use four of them.

Example 4-13. ControllerTest.java
public void testGetBikesWithMocks( ) throws Exception {    DataSource mockDataSource;    Connection mockConnection;    Statement mockStatement;    ResultSet mockRS;    MockControl controlDataSource =        MockControl.createControl(DataSource.class);    MockControl controlConnection =        MockControl.createNiceControl(Connection.class);    MockControl controlStatement =        MockControl.createControl(Statement.class);    MockControl controlRS =        MockControl.createControl(ResultSet.class);          mockDataSource = (DataSource)controlDataSource.getMock( );          mockConnection = (Connection)controlConnection.getMock( );          mockStatement = (Statement)controlStatement.getMock( );          mockRS = (ResultSet)controlRS.getMock( );

Next, you will set the expectations. Using EasyMock, you do this by recording a working version of your intended test case. When you do the record, you're telling EasyMock how the application should behave (Example 4-14).

Example 4-14. ControllerTest.java
      mockDataSource.getConnection( );       controlDataSource.setReturnValue(mockConnection);       mockConnection.createStatement( );       controlConnection.setReturnValue(mockStatement);       mockStatement.executeQuery("SELECT * FROM bikes");       controlStatement.setReturnValue(mockRS);       controlRS.expectAndReturn(mockRS.next( ), false);       controlStatement.expectAndReturn(mockStatement.getWarnings( ),           null);       mockRS.close( );       mockStatement.close( );       mockConnection.close( );

Next, you'll play the test case back, as in Example 4-15.

Example 4-15. ControllerTest.java
      controlConnection.replay( );       controlDataSource.replay( );       controlStatement.replay( );       controlRS.replay( );

Finally, you will kick off the actual test and verify the test case (Example 4-16). If the verification step fails, then the test case will fail, just as if an assertion failed in basic JUnit.

Example 4-16. ControllerTest.java
      JDBCRentABike jstore = (JDBCRentABike)store;       jstore.setDataSource(mockDataSource);       List bikes = store.getBikes( );       controlConnection.verify( );       controlDataSource.verify( );       controlStatement.verify( );       controlRS.verify( );

Let's say that you forgot to record the ResultSet being closed (by leaving out the call mockRS.close( )). Example 4-17 shows the results of running the unit test.

Example 4-17. Output from running ControllerTest.java
junit.framework.AssertionFailedError:    Unexpected method call close( ):     close( ): expected: 0, actual: 1     at org.easymock.internal.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:44)     at $Proxy3.close(Unknown Source)     at org.springframework.jdbc.support.JdbcUtils.closeResultSet(JdbcUtils.java:69)     at org.springframework.jdbc.core.JdbcTemplate$1QueryStatementCallback.doInStatement (JdbcTemplate.java:259)     at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:204)     at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:266)     at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:270)     at com.springbook.JDBCRentABike.getBikes(JDBCRentABike.java:56)     at JDBCFacadeTest.testGetBikesWithMocks(JDBCFacadeTest.java:75)     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)     at com.intellij.rt.execution.junit2.JUnitStarter.main(Unknown Source)

Stubs and Mocks

In Chapter 2, we used an array list instead of a database. Many programmers mistakenly think that this technique is called mocking. Actually, that's not quite true. A stub simulates a real-world scenario, like the array list simulates a database. The stub seeks to make your application lighter, so that it will be easier to run, test, and build: while you're working on other parts of the system, you don't have to keep the database running.

Mock objects are different. Their job is to measure the way an interface is used. You'd use a mock object to verify that a connection gets closed, or that the right query gets called in the first place. When you use a mock strategy, you'll have three distinct steps:


Set expectations

This step has two purposes. First, your object must work with the application in the same way that the real-world code works with the application. While it doesn't have to simulate real-world side effects, it needs to return a correct value. The second part of this step is to define the right stream of calls, including the right parameters and the right order. For example, your expectation step could open a connection, run a query, return a hardcoded result set, and close the connection.


Use the mock object in test conditions

This step records the way your application actually uses the mock API.


Verify the results

This step compares the expectations against the actual use. If they are the same, the test passes. Otherwise, the test fails.

Which is better? That depends on what you need to do. Use stubs to replace heavyweight real-world implementationsfor example, to test a user interface without needing a full database. Make certain test cases shorter. Use mocks to verify the use of an API. Mocks are very good at making sure that cleanup happens correctly, and that APIs are used correctly.


4.5.2. What just happened?

You've seen dynamic mock objects in action. The nice thing about dynamic mock objects is that you can test sophisticated user interfaces, like JDBC, without having to simulate all of its behavior.

4.5.3. What about...

...other mock object frameworks? You don't have to use EasyMock. Other mock object frameworks work as well. The overall flow is the same. For any framework, we'll see the following steps (similar to the ones described in the sidebar above):


Set the expectations for success

A mock object will replace one or more interfaces in an application. It doesn't need to act like the real thing, but it does need to simulate the input and output.


Exercise the mock object

You'll make the object under test do something.


Verify the mock object

You'll then ask the mock object if it was used in the way that you expected.

For some, mock objects might seem to be awkward. Stay with them, and you'll learn to appreciate how they ease your testing burden. Just don't throw away everything else in your toolbox to make room for this, or any other, golden hammer.

You have just seen how to use simple JDBC with Spring. In the next chapter, you'll see how Spring can do many of the same things for other persistence solutions, including full object relational frameworks.

    team bbl



    Spring. A developer's Notebook
    Spring: A Developers Notebook
    ISBN: 0596009100
    EAN: 2147483647
    Year: 2005
    Pages: 90

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