Нагрузочное тестирование базы данных. ContiPerf + DBUnit

Ниже представлен опыт нагрузочного тестирования базы данных с использованием JUnit и ассоциированных с ним DBUnit и ContiPerf.ContiPerfContiPerf — утилита, которая позволяет использовать JUnit4 для нагрузочных тестов. Проста в использовании, легко и разнообразно настраивается. Использует Java аннотации для задания настроек теста и требований выполнения, создает подробный отчет в виде html файла с графиком распределения времени выполнения. Требует использование Java не ниже 5 версии и JUnit не ниже версии 4.7.DBUnit DBUnit — расширение для JUnit, упрощающее тестирование программ, работающих с бд. Впрочем, вполне популярен и в представлении не нуждается, поэтому ограничусь ссылками: знакомство для начинающих, упоминания на хабре. Тест Для начала создадим файл с параметрами подключения к базе данных. Здесь используются Spring JavaConfig и для нагрузочного тестирования необходим пул соединений, в качестве которого выбран Tomcat JDBC Connection Pool. О последнем и способах его использования можно прочитать здесь и здесь. Пул выбирался по принципу первый с примерами в списке google запроса «connection pool». @Configuration @Profile («db1») public class DBConfig { @Bean public javax.sql.DataSource.DataSource dataSource (){ org.apache.tomcat.jdbc.pool.DataSource ds = new org.apache.tomcat.jdbc.pool.DataSource (); ds.setDriverClassName («dbDriver»); ds.setUrl («dbUrl»); ds.setUsername («dbUser»); ds.setPassword (»); ds.setInitialSize (5); ds.setMaxActive (10); ds.setMaxIdle (5); ds.setMinIdle (2); return ds; } } Далее настроим DBUnit. В общей сложности получится два конфигурационных класса. Первый — JavaConf — служит для описания настроек соединения при желании и к нескольким базам данных и далее позволяет легко подключать нужную бд к тесту. Ниже будет создан класс, при наследовании от которого появится возможность использовать уже настроенный функционал DBUnit, и не нужно будет настраивать его каждый раз. Эти классы можно использовать и при другом виде, не только при нагрузочном тестировании. @ContextConfiguration (classes = DBConfig.class) @ActiveProfiles («db1») public class DBUnitConfig extends DBTestCase{ @Autowired javax.sql.DataSource dataSource;

protected IDatabaseTester tester; protected IDataSet beforeData; private TestContextManager testContextManager; @Before public void setUp () throws Exception { this.testContextManager = new TestContextManager (getClass ()); this.testContextManager.prepareTestInstance (this); tester = new DataSourceDatabaseTester (dataSource); } @Override protected IDataSet getDataSet () throws Exception { return beforeData; } @Override protected DatabaseOperation getTearDownOperation () throws Exception { return DatabaseOperation.NONE; } } Здесь используется небольшой трюк. Дело в том, что JUnit позволяет только один раз использовать аннотацию @RunWith, которая будет использована позже, что в свою очередь не позволяет воспользоваться классическим @RunWith (SpringJUnit4ClassRunner.class). Поэтому нужно вручную создавать экземпляр контекста и подтягивать его вот этим участком кода©: // танец с бубном this.testContextManager = new TestContextManager (getClass ()); this.testContextManager.prepareTestInstance (this); Чтобы понять вид используемой здесь магии следует обратиться к документации соответствующего класса.Наконец, переходим непосредственно к тестовому классу:

// как и обещано RunWith использован, здесь для параллельного выполнения тестовых методов @RunWith (ParallelRunner.class) // настройки нагрузочного теста: продолжительность в мс, количество потоков, // время ожидания между тестами в мс (случайно выбирается из указанного интервала) @PerfTest (duration = 10000, threads = 50, timer = RandomTimer.class, timerParams = { 5, 15 }) // требования к тесту: максимальное и среднее время выполнения, не является обязательным полем @Required (max = 500, average = 100) public class PerfTest extends DBUnitConfig { // активация ContiPerf @Rule public ContiPerfRule i = new ContiPerfRule (); // метод для инициализации данных необходимых для теста @Before public void setUp () throws Exception { super.setUp (); // тривиальный пример xml файла набора данных:»» beforeData = new FlatXmlDataSetBuilder ().build ( Thread.currentThread ().getContextClassLoader () .getResourceAsStream («initData.xml»)); tester.setDataSet (beforeData); tester.onSetup (); } // тестовый метод @Test public void test1() { Connection sqlConnection = null; CallableStatement statement = null; ResultSet set = null; try { sqlConnection = tester.getConnection ().getConnection (); sqlConnection.setAutoCommit (true);

statement = sqlConnection.prepareCall («select smth from tbl where param=?»); statement.setString (1, «prm»); set = statement.executeQuery (); set.next (); int smth1 = set.getInt (1); statement.close ();

statement = sqlConnection.prepareCall (»{ ? = call pkg.function (?) }»); statement.registerOutParameter (1, (Types.INTEGER)); statement.setString (2, «prm»); statement.execute (); int smth2 = statement.getInt (1); statement.close (); } catch (Exception ex){ System.out.print (ex.getMessage ()); } finally { try { set.close (); statement.close (); sqlConnection.close ();} catch (Exception e){ System.out.print (e.getMessage ());} } Assert.assertEquals (smth1, smth2); } } В catch, как идея к дополнениям, можно добавить счетчик ошибок и выводить их количество в методе с аннотацией after.Больше настроек для ContiPerf можно найти на официальной странице: можно, например, в аннотации @PerfTest задавать не длительность теста, а количество его выполнения с помощью параметра invocations.Краткий отчет для каждого тестового метода пишется в консоли после выполнения, более детальный отчет (пример приведен ниже) с подробной статистикой находится в файле target/contiperf-report/index.html.imageДля решения данной задачи вначале была попытка использовать инструмент для тестирования SoapUI и JDBC запросы, однако возникла проблема — частое, методичное выпадение ошибки: «java.sql.SQLException: Listener refused the connection with the following error: ORA-12519, TNS: no appropriate service handler found» — не нашедшая решения. Позже нашлось другое решение с использованием другого инструмента — JMeter, но слишком поздно…P.S.: Комментарии, нарекания, дополнения, возражения, напутствия приветствуются и очень полезны.

© Habrahabr.ru