由于各种原因,正在进行中的一个项目,并没有严格遵守测试先行的最佳实践。我们先写功能代码,然后再补充测试代码。
这是一个普通的Java WebApp项目,在服务器端使用的是SpringMVC 3 和 Hibernate 3.6, 按照最一般的层次划分,采用的是MVC + Service + Persistence 的做法。在开发过程中,对于Service这层,初始开发过程中,并没有立即采用面向接口的方式,拟考虑在Service功能代码相对稳定之后,通过重构来抽取接口。
于是起初原始Service层的代码只有 ****ServiceImpl 等诸如这样的类,例如:
......
......
@Service("trxDefService")
@Transactional(readOnly=true)
public class TrxDefServiceImpl {
private static final Logger logger = LoggerFactory.getLogger(TrxDefServiceImpl.class);
private GenericDao<TrxDef, Long> trxDefDao;
......
......
@Autowired
public void setDao(
......
......
@Resource(name="circularCheckingService")
public void setCircularCheckingService(CircularReferenceService circularService) {
this.circularService = circularService;
}
......
......
针对这个Service实现,相关的单元测试代码如下:
......
@ContextConfiguration(locations = {"classpath:/TrxDefServiceImplTest-context.xml"})
public class TrxDefServiceImplTest extends AbstractTransactionalJUnit4SpringContextTests {
private TrxDefServiceImpl trxDefService;
@Autowired
public void setTrxDefService(TrxDefServiceImpl trxDefService) {
this.trxDefService = trxDefService;
}
@Test
public void getAllListener() {
List<Listener> list = trxDefService.getAllListener();
assertNotNull(list);
assertTrue(list.size() >= 0);
}
......
在这里比较有意思的一个现象是,这个TestCase我从Eclipse IDE上运行的时候,测试能够通过;但是从Ant中运行同样的TestCase则会失败,提示报错如下:
"No matching bean of type [foo.bar.tm.trxdef.service.TrxDefServiceImpl] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency."
如果不采用@Autowired的byType形式,而是通过byName的方式注入Service:
private TrxDefServiceImpl trxDefService;
@Resource(name="trxDefService")
public void setTrxDefService(TrxDefServiceImpl trxDefService) {
this.trxDefService = trxDefService;
}
错误提示则更加直观:
"org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named 'trxDefService' must be of type [foo.bar.tm.trxdef.service.TrxDefServiceImpl], but was actually of type [$Proxy34]"
由此看来无论是byType注入还是byName注入,通过Ant启动的JUnit测试总是不通过,从错误消息来看,个人猜测是因为由于没有采用面向接口的方式编程,代码编译时指定的trxDefService类型[foo.bar.tm.trxdef.service.TrxDefServiceImpl] 和 运行时通过(c3p0或者cglib)动态生成的类型 [$Proxy34] 不一致,所以导致service注入失败。
但如果声明了Service接口,[foo.bar.tm.trxdef.service.TrxDefServiceImpl] 和动态代理类[$Proxy??] 都是Service接口的实现,这样的情况下可以正常注入service,测试可以正常运行。
解决上述问题的方式比较简单,从TrxDefServiceImpl上抽取出接口,单元测试代码中的Service声明为接口即可。(我参考了
http://zhongzhihua.iteye.com/blog/613305,很给力)
......
@Service("trxDefService")
@Transactional(readOnly=true)
public class TrxDefServiceImpl implements TrxDefService {
.......
......
@ContextConfiguration(locations = {"classpath:/TrxDefServiceImplTest-context.xml"})
public class TrxDefServiceImplTest extends AbstractTransactionalJUnit4SpringContextTests {
private TrxDefService trxDefService;
@Autowired
public void setTrxDefService(TrxDefService trxDefService) {
this.trxDefService = trxDefService;
}
......
另外我感到好奇的,就是如果不采用接口编程的方式,直接在Eclipse使用JUnit操作运行测试时可以通过的,而通过Ant运行同样的代码则会报错。我初步的猜测是Eclipse在编译的时候,自动帮我做了某些转换。
另外一种可能就是Eclipse在编译工作之外,做了某些手脚:我通过重构,从TrxDefServiceImpl抽取TrxDefService接口的时候,单元测试代码中的原来声明为TrxDefServiceImpl类型的变量trxDefService,被重构为TrxDefService接口类型了,看上去是比较诡异的,至于重构动作时如何关联到单元测试代码TrxDefServiceImplTest,似乎又与@ContextConfiguration(locations = {"classpath:/TrxDefServiceImplTest-context.xml"}) 有关系。
在
http://stackoverflow.com/questions/4805794/failed-to-load-applicationcontext-nosuchbeandefinitionexception-when-running-jun提到的另外一个可能的原因,就是Ant运行JUnit测试的时候,类路径上找不到c3p0或者cglib,从而导致运行失败。
限于个人的才智,对于上述现象的基础原因,暂时只能停留在 知其然不知其所以然 的水平上,作为学习笔记先记录下来;也欢迎这方面有研究的朋友提供好的想法。
分享到:
相关推荐
spring testContext jar包下载,3.0
- **测试类**:定义一个测试类`UserDAOTest`,该类继承自`AbstractTransactionalJUnit4SpringContextTests`或使用`@RunWith(SpringRunner.class)`和`@Transactional`注解来管理事务。 - **测试方法**:编写具体的...
2. **定义测试类**:测试类通常需要继承自 `AbstractTransactionalJUnit4SpringContextTests` 或使用 `@RunWith(SpringRunner.class)` 来集成 Spring 测试框架。 3. **配置 TestExecutionListeners**:可以通过 `@...
在Spring项目中,我们需要创建一个测试配置类,该类通常继承自`AbstractTransactionalDataSourceSpringContextTests`或`AbstractTransactionalJUnit4SpringContextTests`,这两个类提供了事务管理和数据源的自动...
1. **配置Spring测试环境**:使用Spring Test模块,创建一个继承自`AbstractTransactionalDataSourceSpringContextTests`或`AbstractTransactionalJUnit4SpringContextTests`的测试类。这两个类提供了事务管理,确保...
import org.springframework.test.context.junit4.AbstractTransactionalJUnit4SpringContextTests; @ContextConfiguration(locations = { "classpath:spring-context.xml" }) public class MyDatabaseTest extends...
Spring还提供了如`AbstractTransactionalDataSourceSpringContextTests`和`AbstractTransactionalJUnit4SpringContextTests`这样的基类,它们提供了自动事务管理和数据库清理的功能,简化了数据库测试的编写。...
import org.springframework.test.context.junit4.AbstractTransactionalJUnit4SpringContextTests; @ContextConfiguration(locations = {"classpath:spring-context.xml"}) public class DemoEntityTest extends ...
Simple Spring(Core,JPA,ORM,MVC)5个JPA 2 Hibernate 5项目,具有: ...Spring测试:SpringJUnit4ClassRunner + AbstractTransactionalJUnit4SpringContextTests JUnit的 哈姆克雷斯特 莫基托
3. **测试类**:在`src/test/java`目录下,会有测试类,这些类通常继承自Spring的`AbstractTransactionalJUnit4SpringContextTests`或类似的测试基类。测试类会使用DBUnit的`@Before`和`@After`注解来在每个测试开始...