2013-10-19 33 views
6

私はH2データベースに接続し、いくつかのSQL文を実行するクラスを持っています。DriverManager.getConnection(...)をモックする方法は?

public class H2Persistence implements IPersistence { 

    private Connection conn; 

    @Override 
    public void open() { 
     try 
     { 
      Class.forName("org.h2.Driver"); 
      conn = DriverManager.getConnection(CONN_TYPE_USER_HOME); 

      final Statement stmt = conn.createStatement(); 

      stmt.executeUpdate("CREATE TABLE PERSON(" + 
        "ID BIGINT,"+ 
        "AGEGROUP VARCHAR(255),"+ 
        "MONTHLY_INCOME_LEVEL VARCHAR(255)," + 
        "GENDER VARCHAR(1),"+ 
        "HOUSEHOLD_ID BIGINT)"); 

     } catch (ClassNotFoundException e) { 
      e.printStackTrace(); 
     } catch (SQLException e) { 
      e.printStackTrace(); 
     } 
    } 
... 
} 

私はopen方法では、特定のSQL文(DROP TABLE IF EXISTS PERSON)が実行されていることを、確認するユニットテストを書きたいです。

これを行うためには、私がテスト以下の書いた:

import static org.mockito.Mockito.mock; 
import static org.mockito.Mockito.verify; 
import static org.powermock.api.mockito.PowerMockito.mockStatic; 
import static org.powermock.api.mockito.PowerMockito.when; 


@RunWith(PowerMockRunner.class) 
@PrepareForTest(DriverManager.class) 
public class H2PersistenceTest { 
    @Test 
    public void testDropPersonIsCalled() throws SQLException { 
     final Statement statement = mock(Statement.class); 

     final Connection connection = mock(Connection.class); 

     when(connection.createStatement()).thenReturn(statement); 

     mockStatic(DriverManager.class); 

     when(DriverManager.getConnection(H2Persistence.CONN_TYPE_USER_HOME)).thenReturn 
       (connection); 


     final H2Persistence objectUnderTest = new H2Persistence(); 

     objectUnderTest.open(); 
     verify(statement.executeUpdate("DROP TABLE IF EXISTS PERSON")); 
    } 
} 

をしかし、それは動作しません - 代わりに、実際の接続を返しますDriverManagerモック接続、の。

どうすれば修正できますか(DriverManager返信接続模擬テスト)?

ここに私のプロジェクトのpom.xmlがあります。多分何かが間違っています。

<?xml version="1.0" encoding="UTF-8"?> 

<project xmlns="http://maven.apache.org/POM/4.0.0" 
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 
    <modelVersion>4.0.0</modelVersion> 

    <groupId>ru.mycompany</groupId> 
    <artifactId>myproduct</artifactId> 
    <version>1.0-SNAPSHOT</version> 
    <properties> 
     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> 
     <powermock.version>1.5.1</powermock.version> 
     <maven.compiler.source>1.6</maven.compiler.source> 
     <maven.compiler.target>1.6</maven.compiler.target> 
    </properties> 

    <dependencies> 
     <dependency> 
      <groupId>junit</groupId> 
      <artifactId>junit</artifactId> 
      <version>4.10</version> 
      <scope>test</scope> 
     </dependency> 
     <dependency> 
      <groupId>org.easytesting</groupId> 
      <artifactId>fest-util</artifactId> 
      <version>1.2.3</version> 
     </dependency> 
     <dependency> 
      <groupId>org.easytesting</groupId> 
      <artifactId>fest-assert-core</artifactId> 
      <version>2.0M8</version> 
     </dependency> 
     <dependency> 
      <groupId>com.google.guava</groupId> 
      <artifactId>guava</artifactId> 
      <version>15.0</version> 
     </dependency> 
     <dependency> 
      <groupId>org.mockito</groupId> 
      <artifactId>mockito-all</artifactId> 
      <version>1.9.5</version> 
     </dependency> 
     <dependency> 
      <groupId>com.h2database</groupId> 
      <artifactId>h2</artifactId> 
      <version>1.3.173</version> 
     </dependency> 
     <dependency> 
      <groupId>org.powermock</groupId> 
      <artifactId>powermock-module-junit4</artifactId> 
      <version>${powermock.version}</version> 
      <scope>test</scope> 
     </dependency> 
     <dependency> 
      <groupId>org.powermock</groupId> 
      <artifactId>powermock-api-mockito</artifactId> 
      <version>${powermock.version}</version> 
      <scope>test</scope> 
     </dependency> 
    </dependencies> 

</project> 

答えて

6

これは機能します(輸入品に注意してください):

import static org.easymock.EasyMock.expect; 
import static org.mockito.Mockito.mock; 
import static org.mockito.Mockito.verify; 
import static org.mockito.Mockito.when; 
import static org.powermock.api.easymock.PowerMock.mockStatic; 
import static org.powermock.api.easymock.PowerMock.replay; 


@RunWith(PowerMockRunner.class) 
@PrepareForTest({DriverManager.class, H2Persistence.class}) 
public class H2PersistenceTest { 
    @Test 
    public void testDropPersonIsCalled() throws SQLException { 
     final Statement statement = mock(Statement.class); 

     final Connection connection = mock(Connection.class); 

     when(connection.createStatement()).thenReturn(statement); 

     mockStatic(DriverManager.class); 

     expect(DriverManager.getConnection(H2Persistence.CONN_TYPE_USER_HOME)) 
       .andReturn(connection); 
     expect(DriverManager.getConnection(null)) 
       .andReturn(null); 

     replay(DriverManager.class); 
     final H2Persistence objectUnderTest = new H2Persistence(); 

     objectUnderTest.open(); 

     verify(statement).executeUpdate("DROP TABLE IF EXISTS PERSON"); 
     verify(statement).executeUpdate(H2Persistence.CREATE_TABLE_PERSON); 
    } 
} 
0

これを行う通常の方法は、接続の作成を別のクラスに分解し、そのインスタンスを問題のクラスに挿入することです。その新しいクラスを模擬することができます。あなたのケースでは

、このような何か:

public class H2Persistence implements IPersistence { 
    private final ConnectionFactory connectionFactory; 
    private Connection conn; 

    public H2Persistence(ConnectionFactory connectionFactory) { 
     this.connectionFactory = connectionFactory; 
    } 

    @Override 
    public void open() { 
     try { 
      conn = connectionFactory.createConnection(CONN_TYPE_USER_HOME); 
      // etc 
     } 
     catch (ClassNotFoundException e) { 
      e.printStackTrace(); 
     } 
     catch (SQLException e) { 
      e.printStackTrace(); 
     } 
    } 
} 

public class ConnectionFactory { 

    Connection createConnection(String connType) throws SQLException, ClassNotFoundException { 
     Class.forName("org.h2.Driver"); 
     return DriverManager.getConnection(connType); 
    } 

} 

この特定のケースでは、より良いは、おそらく独自の接続ファクトリクラスの代わりに、標準のJDBCインタフェースDataSourceを使用することです:

public class H2Persistence implements IPersistence { 
    private final DataSource dataSource; 
    private Connection conn; 

    public H2Persistence(DataSource dataSource) { 
     this.dataSource = dataSource; 
    } 

    @Override 
    public void open() { 
     try { 
      conn = dataSource.getConnection(); 
      // etc 
     } 
     catch (SQLException e) { 
      e.printStackTrace(); 
     } 
    } 
} 
+0

私はこれを行っていますe(詳細はhttp://altruix.wordpress.com/portfolio/project-control-center/を参照)。問題は、たくさんのクラスを書くと、定型的なコード(インターフェイス、ファクトリインターフェイス、実装など)がたくさんあることになります。だから私はコスト(定型コードの多く)なしでその設計(テスト容易性)の利点を得ようとしました。 –

+0

モックベースのテストを書くときには、このアプローチを取ることは間違いありません。私は、ロジックの多くがモック駆動のリファクタリングの原石によって粉砕されたコードベースで作業します。このケースでは、 'DataSource'が既に存在し、明確に定義された自己完結型の概念を表しており、実装が既にあることを考えると、定型的な過成長のリスクは小さいと思います。 –