Author: bayard
Date: Tue Aug 16 05:51:37 2011
New Revision: 1158110
URL: http://svn.apache.org/viewvc?rev=1158110&view=rev
Log:
Applying William Speirs' patch to move QueryRunnerTest to Mockito (DBUTILS-78)
Modified:
commons/proper/dbutils/trunk/src/test/org/apache/commons/dbutils/QueryRunnerTest.java
Modified:
commons/proper/dbutils/trunk/src/test/org/apache/commons/dbutils/QueryRunnerTest.java
URL:
http://svn.apache.org/viewvc/commons/proper/dbutils/trunk/src/test/org/apache/commons/dbutils/QueryRunnerTest.java?rev=1158110&r1=1158109&r2=1158110&view=diff
==============================================================================
---
commons/proper/dbutils/trunk/src/test/org/apache/commons/dbutils/QueryRunnerTest.java
(original)
+++
commons/proper/dbutils/trunk/src/test/org/apache/commons/dbutils/QueryRunnerTest.java
Tue Aug 16 05:51:37 2011
@@ -16,203 +16,476 @@
*/
package org.apache.commons.dbutils;
-import java.beans.IndexedPropertyDescriptor;
-import java.beans.PropertyDescriptor;
-import java.lang.reflect.InvocationHandler;
-import java.lang.reflect.Method;
-import java.lang.reflect.Proxy;
+import static org.junit.Assert.fail;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.sql.Connection;
import java.sql.ParameterMetaData;
import java.sql.PreparedStatement;
+import java.sql.ResultSet;
import java.sql.SQLException;
-import java.sql.Types;
-import java.util.Arrays;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.RunnableFuture;
+
+import javax.sql.DataSource;
-import junit.framework.TestCase;
+import org.apache.commons.dbutils.handlers.ArrayHandler;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
-public class QueryRunnerTest extends TestCase {
+public class QueryRunnerTest {
QueryRunner runner;
- PreparedStatement stmt;
+ ArrayHandler handler;
+
+ @Mock DataSource dataSource;
+ @Mock Connection conn;
+ @Mock PreparedStatement stmt;
+ @Mock ParameterMetaData meta;
+ @Mock ResultSet results;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this); // init the mocks
+
+ when(dataSource.getConnection()).thenReturn(conn);
+ when(conn.prepareStatement(any(String.class))).thenReturn(stmt);
+ when(stmt.getParameterMetaData()).thenReturn(meta);
+ when(stmt.getResultSet()).thenReturn(results);
+ when(stmt.executeQuery()).thenReturn(results);
+ when(results.next()).thenReturn(false);
+
+ handler = new ArrayHandler();
+ runner = new QueryRunner(dataSource);
+ }
+
+ //
+ // Batch test cases
+ //
+
+ private void callGoodBatch(Connection conn, Object[][] params) throws
Exception {
+ when(meta.getParameterCount()).thenReturn(2);
+ int[] ret = runner.batch(conn, "select * from blah where ? = ?",
params);
+
+ verify(stmt, times(2)).addBatch();
+ verify(stmt, times(1)).executeBatch();
+ verify(stmt, times(1)).close(); // make sure we closed the statement
+ verify(conn, times(0)).close(); // make sure we closed the connection
+ }
+
+ private void callGoodBatch(Object[][] params) throws Exception {
+ when(meta.getParameterCount()).thenReturn(2);
+ int[] ret = runner.batch("select * from blah where ? = ?", params);
+
+ verify(stmt, times(2)).addBatch();
+ verify(stmt, times(1)).executeBatch();
+ verify(stmt, times(1)).close(); // make sure we closed the statement
+ verify(conn, times(1)).close(); // make sure we closed the connection
+ }
+
+ @Test
+ public void testGoodBatch() throws Exception {
+ String[][] params = new String[][] { { "unit", "unit" }, { "test",
"test" } };
+
+ callGoodBatch(params);
+ }
+
+ @Test
+ public void testGoodBatchPmdTrue() throws Exception {
+ runner = new QueryRunner(dataSource, true);
+ String[][] params = new String[][] { { "unit", "unit" }, { "test",
"test" } };
+
+ callGoodBatch(params);
+ }
+
+ @Test
+ public void testGoodBatchDefaultConstructor() throws Exception {
+ runner = new QueryRunner();
+ String[][] params = new String[][] { { "unit", "unit" }, { "test",
"test" } };
+
+ callGoodBatch(conn, params);
+ }
+
+ @Test
+ public void testNullParamsBatch() throws Exception {
+ String[][] params = new String[][] { { null, "unit" }, { "test", null }
};
+
+ callGoodBatch(params);
+ }
+
+
+
+ // helper method for calling batch when an exception is expected
+ private void callBatchWithException(String sql, Object[][] params) throws
Exception {
+ int[] ret = null;
+ boolean caught = false;
+
+ try {
+ ret = runner.batch(sql, params);
+
+ verify(stmt, times(2)).addBatch();
+ verify(stmt, times(1)).executeBatch();
+ verify(stmt, times(1)).close(); // make sure the statement is
closed
+ verify(conn, times(1)).close(); // make sure the connection is
closed
+ } catch(SQLException e) {
+ caught = true;
+ }
+
+ if(!caught)
+ fail("Exception never thrown, but expected");
+ }
+
+ @Test
+ public void testTooFewParamsBatch() throws Exception {
+ String[][] params = new String[][] { { "unit" }, { "test" } };
+
+ callBatchWithException("select * from blah where ? = ?", params);
+ }
+
+ @Test
+ public void testTooManyParamsBatch() throws Exception {
+ String[][] params = new String[][] { { "unit", "unit", "unit" }, {
"test", "test", "test" } };
+
+ callBatchWithException("select * from blah where ? = ?", params);
+ }
+
+ @Test(expected=SQLException.class)
+ public void testNullConnectionBatch() throws Exception {
+ String[][] params = new String[][] { { "unit", "unit" }, { "test",
"test" } };
+
+ when(meta.getParameterCount()).thenReturn(2);
+ when(dataSource.getConnection()).thenReturn(null);
+
+ runner.batch("select * from blah where ? = ?", params);
+ }
+
+ @Test(expected=SQLException.class)
+ public void testNullSqlBatch() throws Exception {
+ String[][] params = new String[][] { { "unit", "unit" }, { "test",
"test" } };
+
+ when(meta.getParameterCount()).thenReturn(2);
+
+ runner.batch(null, params);
+ }
+
+ @Test(expected=SQLException.class)
+ public void testNullParamsArgBatch() throws Exception {
+ when(meta.getParameterCount()).thenReturn(2);
+
+ runner.batch("select * from blah where ? = ?", null);
+ }
+
+ @Test
+ public void testAddBatchException() throws Exception {
+ String[][] params = new String[][] { { "unit", "unit" }, { "test",
"test" } };
+
+ doThrow(new SQLException()).when(stmt).addBatch();
+
+ callBatchWithException("select * from blah where ? = ?", params);
+ }
+
+ @Test
+ public void testExecuteBatchException() throws Exception {
+ String[][] params = new String[][] { { "unit", "unit" }, { "test",
"test" } };
+
+ doThrow(new SQLException()).when(stmt).executeBatch();
+
+ callBatchWithException("select * from blah where ? = ?", params);
+ }
+
+
+ //
+ // Query test cases
+ //
+ private void callGoodQuery(Connection conn) throws Exception {
+ when(meta.getParameterCount()).thenReturn(2);
+ Object[] ret = runner.query(conn, "select * from blah where ? = ?",
handler, "unit", "test");
+
+ verify(stmt, times(1)).executeQuery();
+ verify(results, times(1)).close();
+ verify(stmt, times(1)).close(); // make sure we closed the statement
+ verify(conn, times(0)).close(); // make sure we closed the connection
+
+ // call the other variation of query
+ when(meta.getParameterCount()).thenReturn(0);
+ ret = runner.query(conn, "select * from blah", handler);
+
+ verify(stmt, times(2)).executeQuery();
+ verify(results, times(2)).close();
+ verify(stmt, times(2)).close(); // make sure we closed the statement
+ verify(conn, times(0)).close(); // make sure we closed the connection
+ }
+
+ private void callGoodQuery() throws Exception {
+ when(meta.getParameterCount()).thenReturn(2);
+ Object[] ret = runner.query("select * from blah where ? = ?", handler,
"unit", "test");
+
+ verify(stmt, times(1)).executeQuery();
+ verify(results, times(1)).close();
+ verify(stmt, times(1)).close(); // make sure we closed the statement
+ verify(conn, times(1)).close(); // make sure we closed the connection
+
+ // call the other variation of query
+ when(meta.getParameterCount()).thenReturn(0);
+ ret = runner.query("select * from blah", handler);
+
+ verify(stmt, times(2)).executeQuery();
+ verify(results, times(2)).close();
+ verify(stmt, times(2)).close(); // make sure we closed the statement
+ verify(conn, times(2)).close(); // make sure we closed the connection
+ }
+
+ @Test
+ public void testGoodQuery() throws Exception {
+ callGoodQuery();
+ }
+
+ @Test
+ public void testGoodQueryPmdTrue() throws Exception {
+ runner = new QueryRunner(true);
+ callGoodQuery(conn);
+ }
+
+ @Test
+ public void testGoodQueryDefaultConstructor() throws Exception {
+ runner = new QueryRunner();
+ callGoodQuery(conn);
+ }
+
+
+ // helper method for calling batch when an exception is expected
+ private void callQueryWithException(Object... params) throws Exception {
+ Object[] ret = null;
+ boolean caught = false;
+
+ try {
+ when(meta.getParameterCount()).thenReturn(2);
+ ret = runner.query("select * from blah where ? = ?", handler,
params);
+
+ verify(stmt, never()).close(); // make sure the statement is
still open
+ verify(stmt, times(1)).executeQuery();
+ verify(results, times(1)).close();
+ verify(stmt, times(1)).close(); // make sure we closed the
statement
+ verify(conn, times(1)).close(); // make sure we closed the
connection
+ } catch(SQLException e) {
+ caught = true;
+ }
+
+ if(!caught)
+ fail("Exception never thrown, but expected");
+ }
+
+ @Test
+ public void testNoParamsQuery() throws Exception {
+ callQueryWithException();
+ }
+
+ @Test
+ public void testTooFewParamsQuery() throws Exception {
+ callQueryWithException("unit");
+ }
+
+ @Test
+ public void testTooManyParamsQuery() throws Exception {
+ callQueryWithException("unit", "test", "fail");
+ }
+
+ @Test(expected=SQLException.class)
+ public void testNullConnectionQuery() throws Exception {
+ when(meta.getParameterCount()).thenReturn(2);
+ when(dataSource.getConnection()).thenReturn(null);
+
+ runner.query("select * from blah where ? = ?", handler, "unit", "test");
+ }
+
+ @Test(expected=SQLException.class)
+ public void testNullSqlQuery() throws Exception {
+ when(meta.getParameterCount()).thenReturn(2);
+
+ runner.query(null, handler);
+ }
+
+ @Test(expected=SQLException.class)
+ public void testNullHandlerQuery() throws Exception {
+ when(meta.getParameterCount()).thenReturn(2);
+
+ runner.query("select * from blah where ? = ?", null);
+ }
+
+ @Test
+ public void testExecuteQueryException() throws Exception {
+ doThrow(new SQLException()).when(stmt).executeQuery();
+
+ callQueryWithException(handler, "unit", "test");
+ }
+
+
+ //
+ // Update test cases
+ //
+ private void callGoodUpdate(Connection conn) throws Exception {
+ when(meta.getParameterCount()).thenReturn(2);
+ Integer ret = runner.update(conn, "update blah set ? = ?", "unit",
"test");
+
+ verify(stmt, times(1)).executeUpdate();
+ verify(stmt, times(1)).close(); // make sure we closed the statement
+ verify(conn, times(0)).close(); // make sure we closed the connection
+
+ // call the other variation
+ when(meta.getParameterCount()).thenReturn(0);
+ ret = runner.update(conn, "update blah set unit = test");
+
+ verify(stmt, times(2)).executeUpdate();
+ verify(stmt, times(2)).close(); // make sure we closed the statement
+ verify(conn, times(0)).close(); // make sure we closed the connection
+
+ // call the other variation
+ when(meta.getParameterCount()).thenReturn(1);
+ ret = runner.update(conn, "update blah set unit = ?", "test");
+
+ verify(stmt, times(3)).executeUpdate();
+ verify(stmt, times(3)).close(); // make sure we closed the statement
+ verify(conn, times(0)).close(); // make sure we closed the connection
+ }
- static final Method getParameterCount, getParameterType,
getParameterMetaData;
- static {
- try {
- getParameterCount =
ParameterMetaData.class.getMethod("getParameterCount", new Class[0]);
- getParameterType =
ParameterMetaData.class.getMethod("getParameterType", new Class[]{int.class});
- getParameterMetaData =
PreparedStatement.class.getMethod("getParameterMetaData", new Class[0]);
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
-
- @Override
- public void setUp() {
- runner = new QueryRunner();
- stmt = fakePreparedStatement();
- }
-
- public void testFillStatementWithNull() throws Exception {
- stmt = fakeFillablePreparedStatement(false, new int[] {Types.VARCHAR,
Types.BIGINT});
- runner.fillStatement(stmt, new Object[] { null, null });
- }
-
- public void testFillStatementWithNullOracle() throws Exception {
- stmt = fakeFillablePreparedStatement(true, new int[] {Types.VARCHAR,
Types.BIGINT});
- runner.fillStatement(stmt, new Object[] { null, null });
- }
-
- private PreparedStatement fakeFillablePreparedStatement(final boolean
simulateOracle, final int[] types) throws NoSuchMethodException {
- // prepare a mock ParameterMetaData and a mock PreparedStatement to
return the PMD
- final ParameterMetaData pmd =
mockParameterMetaData(simulateOracle,types);
- InvocationHandler stmtHandler = new InvocationHandler() {
- public Object invoke(Object proxy, Method method, Object[] args)
- throws Throwable {
- if (getParameterMetaData.equals(method)) {
- return pmd;
- }
- return null;
- }
- };
- return ProxyFactory.instance().createPreparedStatement(stmtHandler);
- }
-
- private ParameterMetaData mockParameterMetaData(final boolean
simulateOracle, final int[] types) {
- InvocationHandler pmdHandler = new InvocationHandler() {
- public Object invoke(Object proxy, Method method, Object[] args)
- throws Throwable {
- if (getParameterCount.equals(method)) {
- return Integer.valueOf(types.length);
- }
- if (getParameterType.equals(method)) {
- if (simulateOracle) throw new SQLException("Oracle fails
when you call getParameterType");
- int arg = ((Integer)args[0]).intValue();
- return Integer.valueOf(types[arg-1]);
- }
- return null;
- }
- };
-
- return (ParameterMetaData) Proxy.newProxyInstance(
- pmdHandler.getClass().getClassLoader(),
- new Class[] {ParameterMetaData.class},
- pmdHandler);
- }
-
- public void testFillStatementWithBean() throws SQLException {
- TestBean tb = new TestBean();
- tb.setOne("uno");
- tb.setTwo("dos");
- tb.setThree("tres");
- NoOpFillStatement fakeQueryRunner = new NoOpFillStatement();
- fakeQueryRunner.fillStatementWithBean(stmt, tb, new String[] {"three",
"two", "one"});
- String[] expected = new String[] {"tres", "dos", "uno"};
- assertArrayEquals("Statement filled with incorrect parameters",
expected, fakeQueryRunner.params);
- }
-
- private PreparedStatement fakePreparedStatement() {
- InvocationHandler noOpHandler = new InvocationHandler() {
- public Object invoke(Object proxy, Method method, Object[] args)
- throws Throwable {
- return null;
- }
- };
- PreparedStatement stmt =
ProxyFactory.instance().createPreparedStatement(noOpHandler);
- return stmt;
- }
-
- public void testFillStatementWithBeanErrorNoReadMethod() throws Exception {
- TestBean tb = new TestBean();
- PropertyDescriptor noReadMethod = new PropertyDescriptor("one",
TestBean.class, null, "setOne");
-
- PropertyDescriptor properties[] = new PropertyDescriptor[] {
noReadMethod };
- try {
- runner.fillStatementWithBean(stmt, tb, properties);
- fail("Expected RuntimeException: tried to use a property with no
read method");
- } catch (RuntimeException expected) {}
- }
-
- public void testFillStatementWithBeanErrorBadReadMethod() throws Exception
{
- PropertyDescriptor badReadMethod = new
IndexedPropertyDescriptor("indexed", getClass(), null, null, "getIndexed",
null) {
- @Override
- public synchronized Method getReadMethod() {
- return super.getIndexedReadMethod();
- }
- };
- PropertyDescriptor properties[] = new PropertyDescriptor[] {
badReadMethod };
- try {
- runner.fillStatementWithBean(stmt, this, properties);
- fail("Expected RuntimeException: tried to use a property with no
no-arg read method");
- } catch (RuntimeException expected) {}
- }
-
- public void testFillStatementWithBeanErrorReadMethodThrows() throws
Exception {
- PropertyDescriptor badReadMethod = new
PropertyDescriptor("throwsException", getClass(), "getThrowsException", null);
- PropertyDescriptor properties[] = new PropertyDescriptor[] {
badReadMethod };
- try {
- runner.fillStatementWithBean(stmt, this, properties);
- fail("Expected RuntimeException: tried to call a method that
throws");
- } catch (RuntimeException expected) {}
- }
-
- public void testFillStatementWithBeanErrorReadMethodPrivate() throws
Exception {
- getPrivate();
- PropertyDescriptor badReadMethod = new BadPrivatePropertyDescriptor();
- PropertyDescriptor properties[] = new PropertyDescriptor[] {
badReadMethod };
- try {
- runner.fillStatementWithBean(stmt, this, properties);
- fail("Expected RuntimeException: tried to call a private method");
- } catch (RuntimeException expected) {}
- }
-
- class BadPrivatePropertyDescriptor extends PropertyDescriptor {
- Method getPrivate;
- BadPrivatePropertyDescriptor() throws Exception {
- super("throwsException", QueryRunnerTest.class,
"getThrowsException", null);
- getPrivate = QueryRunnerTest.class.getDeclaredMethod("getPrivate",
new Class[0]);
- }
-
- @Override
- public synchronized Method getReadMethod() {
- if (getPrivate == null) return super.getReadMethod();
- return getPrivate;
- }
- }
-
- public void testRethrowNullMessage() {
- // DBUTILS-40
- SQLException sqe = new SQLException((String)null);
- QueryRunner qr = new QueryRunner();
- try {
- qr.rethrow(sqe, "foo", new Object[] {"bar"});
- fail("rethrow didn't throw");
- } catch (SQLException expected) {}
- }
-
- // indexed bean property
- public String getIndexed(int index) {
- return null;
- }
-
- public String getThrowsException() {
- throw new RuntimeException("this getter always throws an exception");
- }
-
- private String getPrivate() {
- return null;
- }
-
- private void assertArrayEquals(String message, Object[] expected, Object[]
actual) {
- assertEquals(message, Arrays.asList(expected).toString(),
Arrays.asList(actual).toString());
- assertEquals(message, expected.length, actual.length);
- }
-
-
- private class NoOpFillStatement extends QueryRunner {
- Object[] params;
- @Override
- public void fillStatement(PreparedStatement stmt, Object... params)
- throws SQLException {
- this.params = params;
- }
+ private void callGoodUpdate() throws Exception {
+ when(meta.getParameterCount()).thenReturn(2);
+ Integer ret = runner.update("update blah set ? = ?", "unit", "test");
+
+ verify(stmt, times(1)).executeUpdate();
+ verify(stmt, times(1)).close(); // make sure we closed the statement
+ verify(conn, times(1)).close(); // make sure we closed the connection
+
+ // call the other variation
+ when(meta.getParameterCount()).thenReturn(0);
+ ret = runner.update("update blah set unit = test");
+
+ verify(stmt, times(2)).executeUpdate();
+ verify(stmt, times(2)).close(); // make sure we closed the statement
+ verify(conn, times(2)).close(); // make sure we closed the connection
+
+ // call the other variation
+ when(meta.getParameterCount()).thenReturn(1);
+ ret = runner.update("update blah set unit = ?", "test");
+
+ verify(stmt, times(3)).executeUpdate();
+ verify(stmt, times(3)).close(); // make sure we closed the statement
+ verify(conn, times(3)).close(); // make sure we closed the connection
+ }
+
+ @Test
+ public void testGoodUpdate() throws Exception {
+ callGoodUpdate();
+ }
+
+ @Test
+ public void testGoodUpdatePmdTrue() throws Exception {
+ runner = new QueryRunner(true);
+ callGoodUpdate(conn);
+ }
+
+ @Test
+ public void testGoodUpdateDefaultConstructor() throws Exception {
+ runner = new QueryRunner();
+ callGoodUpdate(conn);
+ }
+
+ // helper method for calling batch when an exception is expected
+ private void callUpdateWithException(Object... params) throws Exception {
+ Integer ret = null;
+ boolean caught = false;
+
+ try {
+ when(meta.getParameterCount()).thenReturn(2);
+ ret = runner.update("select * from blah where ? = ?", params);
+
+ verify(stmt, times(1)).executeUpdate();
+ verify(stmt, times(1)).close(); // make sure we closed the
statement
+ verify(conn, times(1)).close(); // make sure we closed the
connection
+ } catch(SQLException e) {
+ caught = true;
+ }
+
+ if(!caught)
+ fail("Exception never thrown, but expected");
+ }
+
+ @Test
+ public void testNoParamsUpdate() throws Exception {
+ callUpdateWithException();
}
+ @Test
+ public void testTooFewParamsUpdate() throws Exception {
+ callUpdateWithException("unit");
+ }
+
+ @Test
+ public void testTooManyParamsUpdate() throws Exception {
+ callUpdateWithException("unit", "test", "fail");
+ }
+
+ @Test(expected=SQLException.class)
+ public void testNullConnectionUpdate() throws Exception {
+ when(meta.getParameterCount()).thenReturn(2);
+ when(dataSource.getConnection()).thenReturn(null);
+
+ runner.update("select * from blah where ? = ?", "unit", "test");
+ }
+
+ @Test(expected=SQLException.class)
+ public void testNullSqlUpdate() throws Exception {
+ when(meta.getParameterCount()).thenReturn(2);
+
+ runner.update(null);
+ }
+
+ @Test
+ public void testExecuteUpdateException() throws Exception {
+ doThrow(new SQLException()).when(stmt).executeUpdate();
+
+ callUpdateWithException("unit", "test");
+ }
+
+ //
+ // Random tests
+ //
+ class MyBean {
+ private int a;
+ private double b;
+ private String c;
+
+ public int getA() { return a; }
+ public void setA(int a) { this.a = a; }
+ public double getB() { return b; }
+ public void setB(double b) { this.b = b; }
+ public String getC() { return c; }
+ public void setC(String c) { this.c = c; }
+ }
+
+ @Test
+ public void testFillStatementWithBean() throws Exception {
+ MyBean bean = new MyBean();
+ when(meta.getParameterCount()).thenReturn(3);
+ runner.fillStatementWithBean(stmt, bean, new String[] { "a", "b", "c"
});
+ }
+
+ @Test(expected=NullPointerException.class)
+ public void testFillStatementWithBeanNullNames() throws Exception {
+ MyBean bean = new MyBean();
+ when(meta.getParameterCount()).thenReturn(3);
+ runner.fillStatementWithBean(stmt, bean, new String[] { "a", "b", null
});
+ }
+
+ @Test(expected=SQLException.class)
+ public void testBadPrepareConnection() throws Exception {
+ runner = new QueryRunner();
+ runner.update("update blah set unit = test");
+ }
}