Seam 使用心得(一)測試先行

最近開始關注Seam,正值Seam2.0發佈之際我也下載來試用,還是準備先做一個用戶註冊的例子。由於一直喜歡TDD所以先從測試用例開始寫起吧。
首先使用seam-gen生成一個項目目錄,然後再進行必要的配置。
1)配置數據源,我使用的hsqldb內存數據庫,這樣比較方便
在myApp-test-ds.xml這樣進行配置
<datasources>
<local-tx-datasource>
<jndi-name>myAppTestDatasource</jndi-name>
<connection-url>jdbc:hsqldb:.</connection-url>
<driver-class>org.hsqldb.jdbcDriver</driver-class>
<user-name>sa</user-name>
<password></password>
</local-tx-datasource>
</datasources>


persistence-test.xml中的配置
<persistence-unit name="myApp" transaction-type="JTA">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>java:/myAppTestDatasource</jta-data-source>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect"/>
<property name="hibernate.hbm2ddl.auto" value="create-drop"/>
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.format_sql" value="false"/>
<property name="hibernate.cache.use_second_level_cache" value="false"/>
<property name="jboss.entity.manager.factory.jndi.name" value="java:/myAppEntityManagerFactory"/>
</properties>
</persistence-unit>


這樣測試數據源的配置就完成了,當然還要把hsqldb.jar放在測試的classpath中。

2)配置測試用例
在測試文件夾中創建一個用於配置測試用例類的xml,我的就是在test/org/qpt/test/user裏面建立一個RegisterTest.xml,內容如下:
<suite name="Register Tests" verbose="2" parallel="false">
<test name="Register Test">
<!--配置jndi數據源,用於數據庫測試-->
<parameter name="datasourceJndiName" value="java:/myAppTestDatasource"/>
<classes>
<class name="org.qpt.test.user.RegisterTest" />
</classes>
</test>
</suite>


3)[color=red]檢查你的build.xml中test任務是否正確的拷貝了測試所有需要用到的jar包和xml文件[/color],我的build.xml是用seam-gen自動生成的,有些文件例如dataset.xml模擬數據庫的標準數據的文件就沒有被自動拷貝到相應的目錄導致運行測試就報異常,我爲此鬱悶了好幾天,網上一直找不到答案,結果靜下心仔細研究了一下才發現build.xml的問題-_-!,所以我在build.xml加入瞭如下任務:
<copy todir="${test.dir}">
<fileset dir="${src.test.dir}">
<exclude name="**/*.java" />
</fileset>
</copy>
<copy tofile="${test.dir}/myApp-ds.xml"
file="${basedir}/resources/myApp-test-ds.xml"
overwrite="true"/>


4)編寫測試用例
一般來說用戶註冊要調用一個register()的業務方法,所以我的無狀態session bean接口如下:

package org.qpt.facade;
import javax.ejb.Local;

@Local
public interface Register {

/**
* 註冊一個新用戶
* @return 狀態碼有5種情況:1,註冊成功(SUCCESS)
* 2,兩次輸入的密碼不同(PWD_NOT_EQ_IN_TWICE)
* 3,兩次輸入的email不同(EMAIL_NOT_EQ_IN_TWICE)
* 4,用戶名已經在數據庫裏面存在(EXISTS_NAME)
* 5,email已經在數據庫裏面存在(EXISTS_EMAIL)
*/
public String register();
}


返回的狀態碼可以用enum來實現,如:
public enum RegState {
EXISTS_EMAIL, EXISTS_NAME, PWD_NOT_EQ_IN_TWICE, EMAIL_NOT_EQ_IN_TWICE, SUCCESS
}

現在就可以在org.qpt.test.user.RegisterTest類裏面開始編寫測試用例了,但是由於使用了ejb所以現在要用到嵌入式jboss,要把jboss-embedded-all.jar放到測試的classpath中。([color=red]注意:根據官方文檔的說明,嵌入式jboss只能在jdk1.5下面使用,如果使用的jdk1.6將報異常,但是經過搜索官方網站已經發現瞭解決方案,那就是要下載一個新的org.jboss.metadata.spi.signature.Signature類重新編譯後覆蓋原始的,這個類的源文件在最後附上[/color])

下面的代碼是測試代碼的一部分,完整的代碼應該驗證register方法返回的5種狀態 :
public class RegisterTest extends DBUnitSeamTest {// 1
@Override
protected void prepareDBUnitOperations() {
beforeTestOperations.add(new DataSetOperation("org/qpt/test/user/RegisterDataSet.xml")); // 2
}
......
@Test
public void testCorrectCase() throws Exception { //3
new FacesRequest() {

@Override
protected void updateModelValues() {
setValue("#{user.name}", "qwerty");
setValue("#{user.pwd}", "123456");
setValue("#{user.confirmPwd}", "123456");
setValue("#{user.email}", "[email protected]");
setValue("#{user.confirmEmail}", "[email protected]");
}

@Override
protected void processValidations() {
validateValue("#{user.name}", "qwerty");
validateValue("#{user.pwd}", "123456");
validateValue("#{user.confirmPwd}", "123456");
validateValue("#{user.email}", "[email protected]");
validateValue("#{user.confirmEmail}", "[email protected]");
assert !isValidationFailure();
}

@Override
protected void invokeApplication() {
assert invokeMethod("#{register.register}").equals("SUCCESS");
}
}.run();
}
@Test
public void testPwdIllegaCase() throws Exception {
new FacesRequest() {

@Override
protected void updateModelValues() {
setValue("#{user.name}", "qwerty");
setValue("#{user.pwd}", "654321");
setValue("#{user.confirmPwd}", "123456");
setValue("#{user.email}", "[email protected]");
setValue("#{user.confirmEmail}", "[email protected]");
}

@Override
protected void invokeApplication() {
assert invokeMethod("#{register.register}").equals("PWD_NOT_EQ_IN_TWICE");
}
}.run();
}
......

@Test
public void testNameExistsCase() throws Exception {
new FacesRequest() {

@Override
protected void updateModelValues() {
setValue("#{user.name}", "hypercube");
setValue("#{user.pwd}", "654321");
setValue("#{user.confirmPwd}", "654321");
setValue("#{user.email}", "[email protected]");
setValue("#{user.confirmEmail}", "[email protected]");
}

@Override
protected void invokeApplication() {
assert invokeMethod("#{register.register}").equals("EXISTS_NAME");
}
}.run();
}

......

}

1,因爲用戶註冊肯定要操作數據庫,所以我繼承了DBUnitSeamTest,這樣就可以方便的使用dbunit和hsqldb內存數據庫進行測試了。
2,繼承DBUnitSeamTest就要實現他的一個抽象方法protected void prepareDBUnitOperations(),主要是使用標準數據初始化數據庫。RegisterDataSet.xml裏面就是定義了表結構和標準數據,我的users表內容如下:
<?xml version="1.0" encoding="UTF-8"?>
<dataset>
<users name="hypercube" pwd="123456" email="[email protected]" />
</dataset>

如果你被有指定其他的操作,DataSetOperation默認使用DatabaseOperation.CLEAN_INSERT作爲一個構造參數。這個例子首先清空定義在BaseData.xml中所有的表然後插入所有聲明在BaseData.xml中的行在@test方法每次調用之前。
3,這個方法模擬了JSF請求的生命週期包括初始化模型的值,驗證模型屬性的合法性(配合hibernate驗證),調用register()方法,然後通過assert驗證方法是否正確的執行。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章