论坛首页 综合技术论坛

初学TDD,小记

浏览 3903 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2008-10-25   最后修改:2009-04-26
回头看了看。。本篇纯属误导人之作。

我正在学TDD,这算是自己做的一个小玩具吧,练手用而已。
我打算做一个Blog,一个Blog的主要功能也就是:保存Blog、删除Blog、查看Blog。OK,先上TODOLIST:
引用
保存BLOG
删除BLOG
查看BLOG具体内容


然后是测试代码,测试保存BLOG:

/**
 * 测试保存BLOG
 */
@Test
public void testSaveBlog(){
	blogService.save(blog);
}


我需要一个Blog,一般Blog都会有标题、内容、创建时间:

/**
 * 测试保存BLOG
 */
@Test
public void testSaveBlog(){
	Blog blog = new Blog();
	blog.setTitle("title");
	blog.setContent("content");
	blog.setCreatedTime(new Date());

	blogService.save(blog);
}


BlogService里的业务逻辑很简单,就是调用DAO保存Blog。有人说调用DAO保存Blog算什么业务逻辑,那只是对Blog的持久化。可是我觉得,在博客这个“领域”,保存一篇博客算是一个业务逻辑吧?只是这个业务逻辑非常简单,我只要测试这个动作有没被执行就可以了。

public class BlogServiceTest extends BaseTest {
	
	private BlogService blogService;
	private BlogDAO blogDAO;
	
	public void setBlogService(BlogService blogService){
		this.blogService = blogService;
	}
	
	@Before
	public void setUp(){
		this.blogService = (BlogService)this.applicationContext.getBean("blogService");
		blogDAO = createMock(BlogDAO.class);
		this.blogService.setBlogDAO(blogDAO);
	}
	
	@After
	public void tearDown(){
		verify(blogDAO);
	}

	/**
	 * 测试保存BLOG
	 */
	@Test
	public void testSaveBlog(){
		Blog blog = new Blog();
		blog.setTitle("title");
		blog.setContent("content");
		blog.setCreatedTime(new Date());

		blogDAO.save(blog);
		
		replay(blogDAO);
		blogService.save(blog);
	}
}


在gigix的什么是“测试驱动开发”中见robbin说replay()前面是详细设计,后面是需求文档,当时没太理解,现在看看代码好像真是这么回事。

现在的测试代码编译不了,需要实现一个Blog:

public class Blog {

	private String id;
	
	private String title;
	
	private String content;
	
	private Date createdTime;

	//Setter
}


一个BlogDAO接口,声明一个save(Blog blog)方法:
public interface BlogDAO {

	/**
	 * 保存Blog
	 * @param blog 要保存的Blog
	 */
	void save(Blog blog);
}


一个BlogService接口,声明一个save(Blog blog)方法、一个setBlogDAO(BlogDAO blogDAO)方法:
public interface BlogService {
	
	/**
	 * Set DAO
	 * @param blogDAO
	 */
	void setBlogDAO(BlogDAO blogDAO);

	/**
	 * 保存Blog
	 * @param blog 要保存的Blog
	 */
	void save(Blog blog);
}


最后导入Spring包,现在测试代码编译通过,但是测试通不过,红条。抛的异常是NullPointerException,找了一会原因,发现还没配置BlogService的实现类,于是写了个BlogService的实现类如下,并在spring配置文件中配上:
public class BlogServiceImpl implements BlogService {

	@Override
	public void save(Blog blog) {
		// TODO Auto-generated method stub

	}

	@Override
	public void setBlogDAO(BlogDAO blogDAO) {
		// TODO Auto-generated method stub

	}

}


由于业务逻辑非常简单(调用dao持久化blog),所以我就不先运行Test,等看见红条后再来修改Service的实现。大步一点,我直接把方法给写完整了:

public class BlogServiceImpl implements BlogService {

	private BlogDAO blogDAO;
	
	@Override
	public void save(Blog blog) {
		blogDAO.save(blog);
	}

	@Override
	public void setBlogDAO(BlogDAO blogDAO) {
		this.blogDAO = blogDAO;
	}

}


最后我觉得应该可以了,运行测试,绿条,通过了,一个功能就完成了。代码很简单,也没什么要重构的。现在划掉TODOLIST上的“保存BLOG”,接下来是“删除BLOG”。
TODOLIST:
引用
保存BLOG
删除BLOG
查看BLOG具体内容


先到这吧,整个过程都是我在自以为是,呵呵。
我想请教论坛里的前辈,这整个过程有没什么问题?
还有单元测试中,Spring是不是这么用的(applicationContext.getBean(beanName))?
希望多多批评,谢谢了!
   发表时间:2008-10-25  
bean基本就这么用么。其实怎么用看你自己的需要咯

单元测试只有一个么?。。。异常情况不需要测试么?。。。e。。。
0 请登录后投票
   发表时间:2008-10-25   最后修改:2008-12-12
WhisperXD 写道
bean基本就这么用么。其实怎么用看你自己的需要咯

单元测试只有一个么?。。。异常情况不需要测试么?。。。e。。。

异常?比如说?
我觉得这么简单的逻辑不包含异常情况吧。你是指Runtime Exception吗?
我觉得业务代码中如果可能抛出业务意义上的异常,就专写个方法测试可能抛出的CatchedException,其余非业务上的异常中如果有CatchedException(一般不会有这种情况,我都会封装成RuntimeException)就直接封装成RuntimeException抛出。
0 请登录后投票
   发表时间:2008-10-25  
e..我个人理解的TDD没啥复杂的东西。。
说白了就是结果驱动咯。
也就是说你先设计出使用到最后会发现的各种可能的结果,并且用junit写出这些结果的junit表示。然后开始编程。
有的放矢,让你从一个使用者+实现者的混合角色变为先从使用者角色设计程序的结果期望,然后再变为实现者去实现他们,这样比较不容易出漏洞,并且效率更高。

那么在我的这种肤浅的认识下。
我认为所有在你处理中会抛出的各种异常,比如ilegalargument啊这些,还有SQL异常啊。等等都做过处理给出正确的反映才是真正一个程序应该做到的。
0 请登录后投票
   发表时间:2008-10-28  
他的方法声明中并没有声明会抛出异常,所以也不必测这种情况了
1 请登录后投票
   发表时间:2009-01-09  
测试步骤错了吧。。

先测试DAO。。。然后再写Service测试。。。


PS:我非常讨厌DAO和Service.
0 请登录后投票
   发表时间:2009-01-09   最后修改:2009-01-09
风花雪月饼 写道
测试步骤错了吧。。

先测试DAO。。。然后再写Service测试。。。

我想我是从一开始就错了。为什么要从Service开始?按你的说法,为什么要从DAO开始?

=========================================
主帖中我的问题,我自己来回答一些:
如何针对接口测试?JUnit中如何使用Spring?可以搜索关键字:AbstractJUnit4SpringContextTests。

至于从哪里开始写测试,这是我的一些思考:http://yuan.iteye.com/blog/312118,由于目前对DDD领悟得还不到位,可能还有些没考虑到的问题。希望最好有人指点一下。
0 请登录后投票
   发表时间:2009-01-09   最后修改:2009-01-09
写什么没顺序.
PS你写多了就会对DAO+SERVICE这种一对一的东西厌恶了.
一般会三到五个dao对应一个service
强大的mock+junit的确让人改起代码来得心应手.
0 请登录后投票
论坛首页 综合技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics