休眠事实:集成测试策略
我喜歡集成測試,這是檢查Hibernate生成哪些幕后花絮的SQL查詢的好方法。 但是集成測試需要運行的數據庫服務器,這是您必須要做的第一選擇。
1.使用類似生產的本地數據庫服務器進行集成測試
對于生產環境,我始終喜歡使用增量DDL腳本,因為我始終可以知道在給定服務器上部署了什么版本,以及哪些是需要部署的較新腳本。 我一直依靠Flyway來為我管理模式更新,對此我非常滿意。
在一個集成測試量很小的小型項目中,您也可以使用類似于生產的本地數據庫服務器進行測試。 這是最安全的選擇,因為它可以確保您在生產設置非常相似的環境下進行測試。
主要缺點是測試速度。 使用外部數據庫意味著額外的時序成本,這很容易在大型項目中失控。 畢竟,誰喜歡每天運行60分鐘的測試程序?
2.內存數據庫集成測試
我選擇使用內存數據庫進行集成測試的原因是為了加快測試的運行時間。 這是影響測試運行時間的一個方面,還有許多其他方面可能會影響您,例如銷毀和重新創建包含大量bean依賴項的Spring應用程序上下文。
您可以選擇許多內存數據庫: HSQLDB , H2 , Apache Derby ,僅舉幾例。
我一直在使用兩種內存中模式生成策略,它們都有優點和缺點,下面將對它們進行解釋。
2.1利用hibernate.hbm2ddl.auto =” update”
Hibernate在配置它時非常靈活。 幸運的是,我們可以使用“ hibernate.hbm2ddl.auto” SessionFactory屬性來自定義DDL生成。
部署架構的最簡單方法是使用“更新”選項。 這對于測試目的很有用。 在生產環境中我不會依賴它,對于增量環境而言,增量DDL腳本是一種更好的方法。
因此,選擇“更新”選項是Integration Testing架構管理的一種選擇。
這就是我在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>我認為Bitronix是我使用過的最可靠的工具之一。 在開發JEE應用程序時,我利用了使用中的Application Server提供的Transaction Manager。 對于基于Spring的項目,我必須雇用獨立的事務管理器,在評估JOTM,Atomikos和Bitronix之后,我選擇了Bitronix。 那是5年前,自從我部署并使用了幾個應用程序以來。
即使應用程序當前僅使用一個數據源,我還是更喜歡使用XA Transactions。 我不必擔心使用JTA會明顯降低性能,因為當當前事務僅使用一個登記的數據源時,Bitronix使用1PC(單階段提交) 。 由于最后一次資源提交的優化,它還可以添加一個非XA數據源。
使用JTA時,建議不要混合使用XA和本地事務,因為并非所有XA數據源都允許在本地事務中進行操作,因此我傾向于盡可能避免這種情況。
不幸的是,就像這種DDL生成方法一樣簡單,它有一個我不太喜歡的缺陷。 我不能禁用“ allowLocalTransactions”設置,因為Hibernate會創建DDL腳本并在XA事務之外對其進行更新。
另一個缺點是,您幾乎無法控制Hibernate代表您部署的DDL腳本,在這種特定的情況下,我不希望犧牲靈活性而不是方便性。
如果您不使用JTA并且不需要決定在當前數據庫服務器上部署哪種DDL模式的靈活性,那么hibernate.hbm2ddl.auto =“ update”可能是您的正確選擇。
2.2靈活的架構部署
此方法包括兩個步驟。 前者將使Hibernate生成DDL腳本,而后者將以自定義方式部署它們。
要生成DDL腳本,我必須使用以下Ant任務(即使正在通過Maven運行),這是因為在編寫本文時,沒有可以使用的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>有了“創建”和“刪除” DDl腳本后,我們現在必須在Spring上下文啟動時部署它們,這是使用以下自定義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>這次我們可以擺脫任何本地交易,因此可以安全地設置:
<property name="allowLocalTransactions" value="false" />- 代碼可在GitHub上獲得 。
翻譯自: https://www.javacodegeeks.com/2013/12/hibernate-facts-integration-testing-strategies.html
總結
以上是生活随笔為你收集整理的休眠事实:集成测试策略的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 小米14配置细节曝光:搭载1mm极窄边框
- 下一篇: 怎么用WiFi桥接路由器让台式电脑上网台