测试驱动开发
测试驱动开发,英文全称Test-Driven Development,简称TDD,是一种不同于传统软件开发流程的新型的开发方法。它要求在编写某个功能的代码之前先编写测试代码,然后只编写使测试通过的功能代码,通过测试来推动整个开发的进行。这有助于编写简洁可用和高质量的代码,并加速开发过程。
传统的的开发流程:
编码--->测试--->重复--->提交
基于测试驱动的开发流程:
测试--->编码--->重复--->提交
下面是一个简单的用户管理的用测试驱动开发的小小例子:
1、先定义好实体类User:
package com.fjnu.model;
public class User {
private String username;
private String password;
private String nickname;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getNickname() {
return nickname;
}
public void setNickname(String nickname) {
this.nickname = nickname;
}
public User() {
super();
// TODO Auto-generated constructor stub
}
public User(String username, String password, String nickname) {
super();
this.username = username;
this.password = password;
this.nickname = nickname;
}
}
2、然后定义好数据操作层的接口IUserService:
package com.fjnu.service;
import com.fjnu.model.User;
public interface IUserService {
public void add(User user);
public void delete(String username);
public User load(String username);
public User login(String username, String password);
}
3、再定义一个异常类UserException,继承RuntimeException。
4、有了这些,就可以针对接口IUserService编写测试类TestUserService了,这个测试类类似于白盒测试,要把各种分支的可能情况都要考虑到并且编写测试代码:
package com.fjnu.service;
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;
import com.fjnu.model.User;
import com.fjnu.model.UserException;
public class TestUserService {
private IUserService us;
private User baseUser;
@Before
public void setUp(){
// 初始化
us = new UserServiceByMap();
baseUser = new User("admin", "123", "管理员");
}
private void assertUserEquals(User u, User tu){
assertEquals("add方法有错误!", u.getUsername(), tu.getUsername());
assertEquals("add方法有错误!", u.getNickname(), tu.getNickname());
assertEquals("add方法有错误!", u.getPassword(), tu.getPassword());
}
@Test
public void testAdd(){
User u = baseUser;
us.add(u);
User tu = us.load("admin");
assertNotNull(tu);
assertUserEquals(u, tu);
//fail("请加入添加的测试代码");
}
@Test(expected=UserException.class)
public void AddExistUsername(){
us.add(baseUser);
User tu = new User("admin", "1234", "alskdf");
us.add(tu);
}
@Test
public void testDelete(){
us.add(baseUser);
User tu = us.load(baseUser.getUsername());
assertNotNull(tu);
us.delete(baseUser.getUsername());
tu = us.load(baseUser.getUsername());
assertNull(tu);
}
@Test
public void testLogin(){
us.add(baseUser);
String username=baseUser.getUsername();
String password=baseUser.getPassword();
User tu = us.login(username, password);
assertUserEquals(baseUser, tu);
}
@Test(expected=UserException.class)
public void testNotExistsUserLogin(){
us.add(baseUser);
String username="admin1";
String password="123";
us.login(username, password);
}
@Test(expected=UserException.class)
public void testPasswordErrorUserLogin(){
us.add(baseUser);
String username="admin";
String password="1235";
us.login(username, password);
}
}
5、编写完测试类之后,就可以实现接口IUserService了:
package com.fjnu.service;
import java.util.HashMap;
import java.util.Map;
import com.fjnu.model.User;
import com.fjnu.model.UserException;
public class UserServiceByMap implements IUserService {
private Map<String, User> us = new HashMap<String, User>();
@Override
public void add(User user) {
// TODO Auto-generated method stub
if(load(user.getUsername()) != null){
throw new UserException("用户名已存在");
}
us.put(user.getUsername(), user);
}
@Override
public void delete(String username) {
// TODO Auto-generated method stub
us.remove(username);
}
@Override
public User load(String username) {
// TODO Auto-generated method stub
return us.get(username);
}
@Override
public User login(String username, String password) {
// TODO Auto-generated method stub
User u = load(username);
if(u==null) throw new UserException("用户名不存在");
if(!u.getPassword().equals(password)) throw new UserException("用户密码不正确");
return u;
}
}
cobertura框架:测试代码覆盖率
用测试驱动开发时,会有一个问题,就是不知道你的测试代码是否覆盖了所有的情况,或者说不知道覆盖了多少。
Cobertura 是一种开源工具,它通过检测基本的代码,并观察在测试包运行时执行了哪些代码和没有执行哪些代码,来测量测试覆盖率。除了找出未测试到的代码并发现 bug 外,Cobertura 还可以通过标记无用的、执行不到的代码来优化代码,还可以提供 API 实际操作的内部信息。
更详细的介绍和使用方法: