2008-11-05 7 views
41

Я хотел бы написать некоторые модульные тесты для некоторого кода, который подключается к базе данных, запускает один или несколько запросов, а затем обрабатывает результаты. (без фактического использования базы данных)Как я могу тестировать код jdbc в java?

Другой разработчик здесь написал нашу собственную реализацию DataSource, Connection, Statement, PreparedStatement и ResultSet, которая вернет соответствующие объекты на основе файла конфигурации xml. (мы могли бы использовать фиктивный источник данных и просто запускать тесты с возвращаемыми наборами результатов).

Разве мы изобретаем колесо здесь? Что-то подобное уже существует для модульного тестирования? Есть ли другие/лучшие способы тестирования кода jdbc?

ответ

22

Вы можете использовать DBUnit вместе с HSQLDB, который может читать свои исходные данные из файлов CSV, например.

+0

Можете ли вы привести примеры? Я ищу примеры, но не могу найти то, что легко отслеживать. Я использую maven. – 2016-09-20 15:49:22

1

DBUnit. Это не позволит вам протестировать ваш код jdbc без базы данных, но похоже, что вы можете ввести другой набор покупок, эмулируя базу данных.

4

Вот почему у вас есть derby (теперь называется JavaDB) или sqlite - это небольшие, простые базы данных, которые вы можете создавать, загружать, тестировать и уничтожать относительно быстро и просто.

+6

Но любой код, который зависит от специфического для поставщика SQL, который не поддерживается легким db, не будет проверен. – Asaph 2011-09-22 18:29:31

+1

@Asaph: «специфический для поставщика SQL» часто является ошибкой. Однако, когда вы отправляетесь тестировать SQL-запрос, специфический для поставщика, вы не выполняете модульное тестирование, так что это не проблема с единичным тестированием, не так ли? – 2011-09-22 19:38:16

+1

Это скорее интеграционный тест, чем единичный тест на тот момент. Но подключение к MySQL в тесте JUnit, возможно, принципиально не отличается от подключения к sqlite из теста JUnit. Я рассматриваю оба сценария как интеграционные тесты. То, что действительно сделало бы это испытание _unit_, будет иметь издевательства или подделки во всех швах базы данных, т.е.нет сервера базы данных (легкий или тяжеловесный). Сказав это, я не фанатик, придерживающийся этого принципа. Пока тесты выполняются быстро и не требуют много ручной настройки, все в порядке со мной. – Asaph 2011-09-22 20:26:50

6

Используйте любую из структур Mock для такой задачи. (jMock, etc.)

Некоторые examples

2

Я бы сказал, что HSQL это путь во время модульных тестов. Цель вашего теста - проверить ваш код jdbc и убедиться, что он работает. Добавление пользовательских классов или издевательство над вызовами jdbc может скрыть ошибки.

В основном я использую mysql, и когда тесты запускают класс драйвера, а URL-адрес изменен на org.hsqldb.jdbcDriver и jdbc: hsqldb: mem: test.

1

Хотя способ издеваться над jdbc в вашем приложении, конечно, зависит от того, как вы осуществили свои фактические транзакции jdbc.

Если вы используете jdbc как есть, я бы предположил, что вы написали себе класс утилиты для выполнения некоторых задач в строке DBUtils.getMetadataFor(String tablename). Это будет означать, что вам нужно будет создать макет этого класса, и это может быть все, что вам нужно. Это было бы довольно простое решение для вас, поскольку у вас, видимо, уже есть серия связанных с jdbc макетных объектов. Обратите внимание, что я предполагаю, что ваш код jdbc не разрывается по всему приложению - если это так, рефакторинг !!!

Если вы используете любую инфраструктуру для обработки базы данных (например, классы шаблонов JDBC Spring Framework), вы можете и должны издеваться над классом интерфейса с помощью EasyMock или другого эквивалента. Таким образом, вы можете иметь всю силу в мире, необходимую для легкой насмешки соединения.

И последнее, если ничего не работает, вы можете сделать то, что уже сказали другие, и использовать DBUnit и/или дерби.

30

У вас есть несколько вариантов:

  • Mock база данных с Mock библиотеки, например JMock. Огромный недостаток этого в том, что ваши запросы и данные, скорее всего, не будут протестированы вообще.
  • Используйте легковую базу данных для испытаний, таких как HSQLDB. Если ваши запросы просты, это, вероятно, самый простой способ.
  • Выделите базу данных для тестов. DBUnit - хороший вариант, или если вы используете Maven, вы также можете использовать sql-maven-plugin для правильной настройки базы данных (будьте осторожны с зависимостями между тестами). Я рекомендую этот вариант, так как он даст вам наибольшую уверенность в том, что запросы будут работать правильно с вашим поставщиком db.

Иногда необходимо и полезно настроить эти тесты таким образом, чтобы эти тесты выполнялись только в том случае, если база данных доступна. Это может быть выполнено, например, строить свойства.

2

Я предпочитаю использовать EasyMock для тестирования не очень простой в обращении код.

0

Мы используем Mockrunner. http://mockrunner.sourceforge.net/ Он имеет ложные соединения и источники данных, встроенные, поэтому нет необходимости реализовывать их сами.

8

Мне нравится использовать комбинацию:

Вы можете получить довольно далеко только с DBUnit и HSQLDB. Unitils предоставляет последнюю милю кода для управления и сброса состояния базы данных. Он также обеспечивает хороший способ управления изменениями схемы базы данных и упрощает использование определенных RBDMS (Oracle, DB2, SQL Server и т. Д.). Наконец, Unitils предоставляет несколько хороших оберток вокруг DBUnit, который модернизирует API и упрощает работу с DBUnit.

Если вы еще не проверили Unitils, вам обязательно нужно. Унилиды часто упускают из виду и недооценивают.

0

водитель чтец может быть использован для макете соединения JDBC, управляя его во время испытаний и возврата данных в виде результирующего набора (с его типизированного списка строк API): https://github.com/cchantep/acolyte

1

Если вы хотите сделать юнит-тесты, а не интеграционные тесты, чем вы можете использовать очень простой и простой подход, используя только Mockito, как это:

public class JDBCLowLevelTest { 

    private TestedClass tested; 
    private Connection connection; 
    private static Driver driver; 

    @BeforeClass 
    public static void setUpClass() throws Exception { 
     // (Optional) Print DriverManager logs to system out 
     DriverManager.setLogWriter(new PrintWriter((System.out))); 

     // (Optional) Sometimes you need to get rid of a driver (e.g JDBC-ODBC Bridge) 
     Driver configuredDriver = DriverManager.getDriver("jdbc:odbc:url"); 

     System.out.println("De-registering the configured driver: " + configuredDriver); 
     DriverManager.deregisterDriver(configuredDriver); 

     // Register the mocked driver 
     driver = mock(Driver.class); 
     System.out.println("Registering the mock driver: " + driver); 
     DriverManager.registerDriver(driver); 
    } 

    @AfterClass 
    public static void tearDown() throws Exception { 
     // Let's cleanup the global state 
     System.out.println("De-registering the mock driver: " + driver); 
     DriverManager.deregisterDriver(driver); 
    } 

    @Before 
    public void setUp() throws Exception { 
     // given 
     tested = new TestedClass(); 

     connection = mock(Connection.class); 

     given(driver.acceptsURL(anyString())).willReturn(true); 
     given(driver.connect(anyString(), Matchers.<Properties>any())) 
       .willReturn(connection); 

     given(connection.prepareCall(anyString())).willReturn(statement);   
    } 
} 

чем вы можете проверить различные сценарии, как и в любом другом Mockito тест, например,

@Test 
public void shouldHandleDoubleException() throws Exception { 
    // given 
    SomeData someData = new SomeData(); 

    given(connection.prepareCall(anyString())) 
      .willThrow(new SQLException("Prepare call")); 
    willThrow(new SQLException("Close exception")).given(connection).close(); 

    // when 
    SomeResponse response = testClass.someMethod(someData); 

    // then 
    assertThat(response, is(SOME_ERROR)); 
}