Appfuse开发实践(三) —— 创建Manager类
第二部分:创建Managers - 创建一个Business Facades调用数据库管理层(DAOs)类并且处理事务(transaction)管理。
阅读本文前最好阅读前一部分:Appfuse开发实践(二)—— 创建DAO对象。
本文将展示如何创建Business Facade class (包括一个JUnit单元测试),它将调用在第一部分创建的DAO类。 再Appfuse的结构里,我们把这个对象叫做Manager类。这个层次的主要职责是作为持久化层(DAO)和web 层之间的桥梁,可以用来解除应用程序表示层(不仅包括web 层,也包括数据库层)和数据库层的耦合度。Manager类也是在应用程序总体结构中放置业务逻辑处理实现代码的地方。
接下来就开始在Appfuse架构下创建一个新的ManagerTest类和一个Manager类。
内容提要:
[1] 创建一个ManagerTest类以运行JUnit测试以对Manager方法进行单元测试
[2] 创建一个调用DAO类的Manager类
[3] 在Spring中配置新创建的Manager指定这个Manager的事务(Transactions)管理对象
[4] 运行ManagerTest
1、创建一个ManagerTest对象以能够用JUnit来测试Manager对象
在第一部分, 我们创建了一个Person对象和一个PersonDAO对象 - 接下来我们继续后面的开发。首先创建一个JUnit对象测试PersonManager. 在test/service/**/service目录下创建PersonManagerTest对象. 我们将要测试DAO对象的基本方法(get, save, remove)。
这个看起来是个多余的步骤(所有的东西都要测试!), 但是这些测试在接下来的半年里都是有极大价值的。
这个对象需要继承service包里面的BaseManagerTestCase 对象。父对象(BaseManagerTestCase)有一个和BaseDAOTestCase对象一样的方法 - 加载properties并对*Test.class对象中对应的属性赋值, 和ApplicationContext一起初始化。
我通常复制(open → save as)也各已经写好的对象test (i.e. UserManagerTest.java) 用查找/替换来实现我需要的新对象。
下面的代码是一个基本的Manager的JUnit测试. 下面的代码来创建和销毁 PersonManager对象. "ctx" 对象是在BaseManagerTestCase 中初始化的.。
import org.myApp.model.Person;
import org.springframework.dao.DataAccessException;
public class PersonManagerTest extends BaseManagerTestCase {
private Person person = null;
private PersonManager mgr = null;
protected void setUp() throws Exception {
super.setUp();
mgr = (PersonManager) ctx.getBean("personManager");
}
protected void tearDown() throws Exception {
super.tearDown();
mgr = null;
}
}
我们实现了JUnit框架要求的基本方法,接下来补充新的测试方法以保证Manger类各个方法都能正常工作。
...我们建立的所有测试方法都以"test" (全部小写)开头。这些方法必须是public类型的,不带任何参数也没有任何返回值,这样就能被定义在Ant build.xml的junit任务自动调用。这里给出的是关于CRUD操作的简单测试方法。一件重要的注意事项时每个方法应该是独立的(跟其他测试方法没有关系)。
在PersonManagerTest.java文件中增加下面的方法:
person = mgr.getPerson("1");
assertNotNull(person.getFirstName());
}
public void testSavePerson() throws Exception {
person = mgr.getPerson("1");
person.setFirstName("test");
mgr.savePerson(person);
assertEquals(person.getFirstName(), "test");
}
public void testAddAndRemovePerson() throws Exception {
person = new Person();
person = (Person) populate(person);
mgr.savePerson(person);
assertEquals(person.getFirstName(), "Bill");
assertNotNull(person.getId());
log.debug("removing person, personId: " + person.getId());
mgr.removePerson(person.getId().toString());
try {
person = mgr.getPerson(person.getId().toString());
fail("Person found in database");
} catch (DataAccessException dae) {
log.debug("Expected exception: " + dae.getMessage());
assertNotNull(dae);
}
}
不过这个类还不能通过编译,因为我们还没有创建PersonManager接口。
2、创建一个Manager对象访问DAO对象
首先应该在src/service/**/service目录下创建PersonManager.java接口,并且为实现类声明基本的CRUD方法。I've eliminated the JavaDocs in the class below for display purposes.
import org.myApp.model.Person;
public interface PersonManager {
public Person getPerson(String id);
public void savePerson(Person person);
public void removePerson(String id);
}
接下来创建PersonManagerImpl类实现PersonManager接口的基本方法。在src/service/**/service/impl目录下创建PersonManagerImpl.java文件。这个类要继承BaseManager类并且实现PersonManager接口。
import org.myApp.model.Person;
import org.myApp.dao.PersonDAO;
import org.myApp.service.PersonManager;
public class PersonManagerImpl extends BaseManager implements PersonManager {
private PersonDAO dao;
public void setPersonDAO(PersonDAO dao) {
this.dao = dao;
}
public Person getPerson(String id) {
return dao.getPerson(Long.valueOf(id));
}
public Person savePerson(Person person) {
dao.savePerson(person);
}
public void removePerson(String id) {
dao.removePerson(Long.valueOf(id));
}
}
需要说明的是setPersonDAO方法。这是方便Spring对Manager对象的PersonDAO属性赋值。这个可以在applicationContext-service.xml 文件中配置。我们接下来会在第三步中说明如何配置[3]。现在可以用"ant compile-service"编译所有创建的对象了。
Finally, we need to create the 最后需要在test/service/**/service目录下创建PersonManagerTest.properties文件以便 person = (Person) populate(person); 能够正常工作。
firstName=Bill
lastName=Joy
我们现在可以为业务逻辑层改写Spring配置文件了,增加对新建对象的支持。
3、为这个Manager和事务配置Spring
打开src/service/**/service/applicationContext-service.xml文件,在文件末尾追加下面的内容。
<property name="target">
<bean class="org.myApp.service.impl.PersonManagerImpl" autowire="byName"/>
</property>
</bean>
4、运行ManagerTest
保存所有编辑好的文件运行ant test-service -Dtestcase=PersonManager任务。
出错了,配置文件中applicationContext-service.xml的类找不到。
检查看到service错误的拼成了secvice。
修改重新运行测试。
测试未通过,getPerson方法取得了null对象,
恩~~,应该重新创建数据库???否则编号就错了....
运行ant setup-db 然后运行ant test-service -Dtestcase=PersonManager还是出错了
仔细检查,
恩,在applicationContext-service.xml文件中没有指定personManager对象personDAO的值~~,修改如下
<property name="target">
<bean class="com.vicfuture.service.impl.PersonManagerImpl" autowire="byName">
<property name="personDAO"><ref bean="personDAO"/></property>
</bean>
</property>
</bean>
看来配置文件中的大小写以及和类中属性名称是否一致应该仔细检查.....
再次运行ant test-service -Dtestcase=PersonManager
出错了,错误变了
[junit] Testcase: testAddAndRemovePerson(com.myapp.service.PersonManager
Test): FAILED
[junit] expected:<Matt> but was:<Bill>
[junit] junit.framework.ComparisonFailure: expected:<Matt> but was:<Bill>
检查PersonManagerTest和PersonManagerTest.properties文件。
想起来,把PersonDAOTest.propertise修改过来没有修改内容,赶紧修改。
再次运行ant test-service -Dtestcase=PersonManager
OK,成功了,
BUILD SUCCESSFUL
Total time: 23 seconds