Hibernate事实:集成测试策略
我喜歡集成測(cè)試,這是檢查Hibernate生成哪些幕后花絮SQL查詢的好方法。 但是集成測(cè)試需要運(yùn)行的數(shù)據(jù)庫服務(wù)器,這是您必須要做的第一選擇。
1.使用類似生產(chǎn)的本地?cái)?shù)據(jù)庫服務(wù)器進(jìn)行集成測(cè)試
對(duì)于生產(chǎn)環(huán)境,我始終喜歡使用增量DDL腳本,因?yàn)槲沂冀K可以知道在給定服務(wù)器上部署了哪個(gè)版本,以及哪些是需要部署的較新腳本。 我一直依靠Flyway來為我管理模式更新,對(duì)此我非常滿意。
在集成測(cè)試量很小的小型項(xiàng)目中,您也可以使用類似于生產(chǎn)的本地?cái)?shù)據(jù)庫服務(wù)器進(jìn)行測(cè)試。 這是最安全的選擇,因?yàn)樗梢源_保您在生產(chǎn)設(shè)置非常相似的環(huán)境中進(jìn)行測(cè)試。
主要缺點(diǎn)是測(cè)試速度。 使用外部數(shù)據(jù)庫意味著額外的時(shí)序成本,這很容易在大型項(xiàng)目中失控。 畢竟,誰喜歡每天運(yùn)行60分鐘的測(cè)試程序?
2.內(nèi)存數(shù)據(jù)庫集成測(cè)試
我選擇使用內(nèi)存數(shù)據(jù)庫進(jìn)行集成測(cè)試的原因是為了加快測(cè)試的運(yùn)行時(shí)間。 這是一個(gè)影響測(cè)試運(yùn)行時(shí)間的方面,還有許多其他方面可能會(huì)影響您,例如銷毀和重新創(chuàng)建包含大量Bean依賴項(xiàng)的Spring應(yīng)用程序上下文。
您可以選擇許多內(nèi)存數(shù)據(jù)庫: HSQLDB , H2 , Apache Derby ,僅舉幾例。
我一直在使用兩種內(nèi)存中架構(gòu)生成策略,它們都有優(yōu)點(diǎn)和缺點(diǎn),下面將對(duì)它們進(jìn)行解釋。
2.1利用hibernate.hbm2ddl.auto =” update”
Hibernate在配置它時(shí)非常靈活。 幸運(yùn)的是,我們可以使用“ hibernate.hbm2ddl.auto” SessionFactory屬性來自定義DDL生成。
部署架構(gòu)的最簡(jiǎn)單方法是使用“更新”選項(xiàng)。 這對(duì)于測(cè)試目的很有用。 在生產(chǎn)環(huán)境中我不會(huì)依賴它,對(duì)于增量環(huán)境而言,增量DDL腳本是一種更好的方法。
因此,選擇“更新”選項(xiàng)是Integration Testing架構(gòu)管理的一種選擇。
這就是我在Hibernate Facts代碼示例中使用它的方式。
讓我們從JPA配置開始,您可以在META-INF / persistence.xml文件中找到:
<?xml version="1.0" encoding="UTF-8"?> <persistence version="2.0"xmlns="http://java.sun.com/xml/ns/persistence"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"><persistence-unit name="testPersistenceUnit" transaction-type="JTA"><provider>org.hibernate.ejb.HibernatePersistence</provider><exclude-unlisted-classes>false</exclude-unlisted-classes><properties><property name="hibernate.archive.autodetection"value="class, hbm"/><property name="hibernate.transaction.jta.platform"value="org.hibernate.service.jta.platform.internal.BitronixJtaPlatform" /><property name="hibernate.dialect"value="org.hibernate.dialect.HSQLDialect"/><em><property name="hibernate.hbm2ddl.auto"value="update"/></em><property name="hibernate.show_sql"value="true"/></properties></persistence-unit> </persistence>并且dataSource配置如下所示:
<bean id="dataSource" class="org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy"><constructor-arg><bean class="bitronix.tm.resource.jdbc.PoolingDataSource" init-method="init"destroy-method="close"><property name="className" value="bitronix.tm.resource.jdbc.lrc.LrcXADataSource"/><property name="uniqueName" value="testDataSource"/><property name="minPoolSize" value="0"/><property name="maxPoolSize" value="5"/><property name="allowLocalTransactions" value="true" /><property name="driverProperties"><props><prop key="user">${jdbc.username}</prop><prop key="password">${jdbc.password}</prop><prop key="url">${jdbc.url}</prop><prop key="driverClassName">${jdbc.driverClassName}</prop></props></property></bean></constructor-arg></bean>我認(rèn)為Bitronix是我使用過的最可靠的工具之一。 在開發(fā)JEE應(yīng)用程序時(shí),我利用了使用中的Application Server提供的Transaction Manager。 對(duì)于基于Spring的項(xiàng)目,我必須雇用獨(dú)立的事務(wù)管理器,在評(píng)估JOTM,Atomikos和Bitronix之后,我選擇了Bitronix。 那是5年前,自從我部署并使用了幾個(gè)應(yīng)用程序以來。
即使應(yīng)用程序當(dāng)前僅使用一個(gè)數(shù)據(jù)源,我還是更喜歡使用XA Transactions。 我不必?fù)?dān)心使用JTA會(huì)明顯降低性能,因?yàn)楫?dāng)當(dāng)前事務(wù)僅使用一個(gè)登記的數(shù)據(jù)源時(shí),Bitronix使用1PC(單階段提交) 。 由于最后一次資源提交的優(yōu)化,它還可以添加多達(dá)一個(gè)非XA數(shù)據(jù)源。
使用JTA時(shí),建議不要混合使用XA和本地事務(wù),因?yàn)椴⒎撬蠿A數(shù)據(jù)源都允許在本地事務(wù)中進(jìn)行操作,因此我傾向于盡可能避免這種情況。
不幸的是,就像這種DDL生成方法一樣簡(jiǎn)單,它有一個(gè)我不太喜歡的缺陷。 我不能禁用“ allowLocalTransactions”設(shè)置,因?yàn)镠ibernate會(huì)創(chuàng)建DDL腳本并在XA事務(wù)之外對(duì)其進(jìn)行更新。
另一個(gè)缺點(diǎn)是,您幾乎無法控制Hibernate代表您部署的DDL腳本,并且在這種特定情況下,我不希望犧牲靈活性而不是方便性。
如果您不使用JTA并且不需要靈活決定將在當(dāng)前數(shù)據(jù)庫服務(wù)器上部署什么DDL模式,那么hibernate.hbm2ddl.auto =” update”可能是您的正確選擇。
2.2靈活的架構(gòu)部署
此方法包括兩個(gè)步驟。 前者將使Hibernate生成DDL腳本,而后者將以自定義方式部署它們。
要生成DDL腳本,我必須使用以下Ant任務(wù)(即使正在通過Maven運(yùn)行),這是因?yàn)樵诰帉懕疚臅r(shí),我沒有可以使用的Hibernate 4 Maven插件:
<plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-antrun-plugin</artifactId><executions><execution><id>generate-test-sql-scripts</id><phase>generate-test-resources</phase><goals><goal>run</goal></goals><configuration><tasks><property name="maven_test_classpath" refid="maven.test.classpath"/><path id="hibernate_tools_path"><pathelement path="${maven_test_classpath}"/></path><property name="hibernate_tools_classpath" refid="hibernate_tools_path"/><taskdef name="hibernatetool"classname="org.hibernate.tool.ant.HibernateToolTask"/><mkdir dir="${project.build.directory}/test-classes/hsqldb"/><hibernatetool destdir="${project.build.directory}/test-classes/hsqldb"><classpath refid="hibernate_tools_path"/><jpaconfiguration persistenceunit="testPersistenceUnit"propertyfile="src/test/resources/META-INF/spring/jdbc.properties"/><hbm2ddl drop="false" create="true" export="false"outputfilename="create_db.sql"delimiter=";" format="true"/><hbm2ddl drop="true" create="false" export="false"outputfilename="drop_db.sql"delimiter=";" format="true"/></hibernatetool></tasks></configuration></execution></executions>... </plugin>有了“創(chuàng)建”和“刪除” DDl腳本后,我們現(xiàn)在必須在Spring上下文啟動(dòng)時(shí)部署它們,這是使用以下定制Utility類完成的:
public class DatabaseScriptLifecycleHandler implements InitializingBean, DisposableBean {private final Resource[] initScripts;private final Resource[] destroyScripts;private JdbcTemplate jdbcTemplate;@Autowiredprivate TransactionTemplate transactionTemplate;private String sqlScriptEncoding = "UTF-8";private String commentPrefix = "--";private boolean continueOnError;private boolean ignoreFailedDrops;public DatabaseScriptLifecycleHandler(DataSource dataSource,Resource[] initScripts,Resource[] destroyScripts) {this.jdbcTemplate = new JdbcTemplate(dataSource);this.initScripts = initScripts;this.destroyScripts = destroyScripts;}public void afterPropertiesSet() throws Exception {initDatabase();}public void destroy() throws Exception {destroyDatabase();}public void initDatabase() {final ResourceDatabasePopulator resourceDatabasePopulator = createResourceDatabasePopulator();transactionTemplate.execute(new TransactionCallback<Void>() {@Overridepublic Void doInTransaction(TransactionStatus status) {jdbcTemplate.execute(new ConnectionCallback<Void>() {@Overridepublic Void doInConnection(Connection con) throws SQLException, DataAccessException {resourceDatabasePopulator.setScripts(getInitScripts());resourceDatabasePopulator.populate(con);return null;}});return null;}});}public void destroyDatabase() {final ResourceDatabasePopulator resourceDatabasePopulator = createResourceDatabasePopulator();transactionTemplate.execute(new TransactionCallback<Void>() {@Overridepublic Void doInTransaction(TransactionStatus status) {jdbcTemplate.execute(new ConnectionCallback<Void>() {@Overridepublic Void doInConnection(Connection con) throws SQLException, DataAccessException {resourceDatabasePopulator.setScripts(getDestroyScripts());resourceDatabasePopulator.populate(con);return null;}});return null;}});}protected ResourceDatabasePopulator createResourceDatabasePopulator() {ResourceDatabasePopulator resourceDatabasePopulator = new ResourceDatabasePopulator();resourceDatabasePopulator.setCommentPrefix(getCommentPrefix());resourceDatabasePopulator.setContinueOnError(isContinueOnError());resourceDatabasePopulator.setIgnoreFailedDrops(isIgnoreFailedDrops());resourceDatabasePopulator.setSqlScriptEncoding(getSqlScriptEncoding());return resourceDatabasePopulator;} }配置為:
<bean id="databaseScriptLifecycleHandler" class="vladmihalcea.util.DatabaseScriptLifecycleHandler"depends-on="transactionManager"><constructor-arg name="dataSource" ref="dataSource"/><constructor-arg name="initScripts"><array><bean class="org.springframework.core.io.ClassPathResource"><constructor-arg value="hsqldb/create_db.sql"/></bean></array></constructor-arg><constructor-arg name="destroyScripts"><array><bean class="org.springframework.core.io.ClassPathResource"><constructor-arg value="hsqldb/drop_db.sql"/></bean></array></constructor-arg> </bean>這次我們可以擺脫任何本地交易,因此可以安全地設(shè)置:
<property name="allowLocalTransactions" value="false" />- 代碼可在GitHub上獲得 。
翻譯自: https://www.javacodegeeks.com/2013/12/hibernate-facts-integration-testing-strategies.html
總結(jié)
以上是生活随笔為你收集整理的Hibernate事实:集成测试策略的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux查看内存进程(linux查看内
- 下一篇: 退役士兵备案(退役后备案)