2013-10-19 6 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'가 이미 존재하고, 잘 정의되고, 자체 포함 된 개념을 나타내며, 이미 구현되어 있다면, 상용구의 과다 성장의 위험은 적다고 생각할 것입니다. –

관련 문제