2009年7月27日
测试1:测试网页是否存在:
要测试一個网页是否存在,只要简单的通过WebConversation的getResponse()方法即可,例如:
WebConversation webConversation = new WebConversation();
webConversation.getResponse(
牋牋牋牋牋牋 "http://localhost:8080/httpUnit/");
如果找不到网页,則會引发HttpNotFoundException,由于不是断言错误,所以这会在JUnit中产生一個Error。
测试2:Get、Post:
您可以分別使用GetMethodWebRequest或PostMethodWebRequest來发出Get或Post请求,例如:
WebConversation webConversation = new WebConversation();
WebRequest request =new GetMethodWebRequest("http://localhost:8080/httpUnit/");
WebResponse response =webConversation.getResponse(request);
要在请求中加上參數,可以使用setParamter()方法,例如:
request.setParameter("username","taobaoge");
测试3:取得表格信息:
您可以从WebResponse中取得相关的HTML信息,假设网页中有如下这样的一个表格:
| 书籍名称 | 设计模式(Design Pattern) |
| 软件版本 | 无 |
| 书籍版次 | 第二版 |
| 修改时间 | 2004/12/26 |
下面的程序演示如何取得表格相关信息进行测试:
WebConversation webConversation = new WebConversation();
WebResponse response = webConversation.getResponse("http://localhost:8080/httpUnit/tableTest.jsp");
WebTable webTable = response.getTables()[0];
assertEquals(2, webTable.getColumnCount());
TableCell cell = webTable.getTableCell(2, 0);
assertEquals("书籍版次", cell.getText());
测试4:跟随超链接:
网页中有很多的超链接,我们可以使用HttpUnit来模拟超链接的点击,例如网页中如果有个超链接如下:
<a href="httpUnitABC.jsp">HttpUnit ABC</a>
则可以使用下面的程序来吵到链接,然后模拟一个click动作来跟随这个超链接:
WebConversation webConversation = new WebConversation();
WebResponse response = webConversation.getResponse("http://localhost:8080/httpUnit/");
WebLink link = response.getLinkWith("HttpUnit ABC");
WebRequest clickRequest = link.getRequest();
WebResponse linkPage =webConversation.getResponse(clickRequest);
测试5:测试Cookie:
如果被测试的网页需要Cookie信息,您可以使用WebConversation的addCookie()方法发送Cookie信息
给网页,例如:
WebConversation webConversation = new WebConversation();
webConversation.addCookie("user", "taobaoge");
WebResponse response = webConversation.getResponse("http://localhost:8080/httpUnit/");
如果网页中包含了Cookie,您可以使用getCookieValue()方法取得网页中包含的Cookie信息,若网页包括下面的Scriptlet:
<%
Cookie cookie = new Cookie("customerId", "12345");
response.addCookie(cookie);
%>
可使用下面的方式來测试传回的Cookie信息:
assertEquals("taobaoge",webConversation.getCookieValue("user"));
测试6:Authorization:
如果您的网页中有预设的HTTP基本验证,则可以使用WebConversation的setAuthorization ()方法來设定验证信息,例如:
webConversation.setAuthorization("justin", "123456");
测试7:设定代理:
有的時候,您测试的目的网页可能必须通过代理服务器才能连上,你可以通过设定系统属性来设定HttpUnit使用代理,例如:
System.getProperties().put("proxySet", "true");
System.getProperties().put("proxyHost", "proxy.ntu.edu.tw");
System.getProperties().put("proxyPort", "8080");
如此之來,HttpUnit就會通过指定的代理服务器來发送请求与接受相应。
1.EasyMock总览:
接下来,让我告诉大家如何使用JUnit和EasyMock框架来进行单元测试。
我们的第一个例子非常简单,但是在现实情况下,你通常是在一些类里使用另外的一些类。在进行真正的测试之前,你可能需要做很多的工作,比喻说安置大量的环境代码,启动一种大型的、复杂的系统,可能是数据库、功过刘或者是某一种类型的IDE环境,你的预设环境代码需要是系统进入某种特定的状态,以便按照测试所需要的方法进行响应。但是这种工作不大可能很快就能完成。
为了对一部分类进行单元测试,你需要建立和控制另外一些类。最好的办法就是为需要测试的类创建一个模拟对象。你可以自己手工的编写类,也可以使用EasyMock来产生这些对象。
模拟对象提供了一种经过证明是成功的解决方案。当我们很难或不可能为某种难以处理的资源创建需要的状态或者存取某种资源受限时,你就可以使用模拟对象。
模拟对象取代真实对象的位置,用于测试一些与真实对象进行交互或依赖于真实对象的功能。模拟对象背后的基本思想就是创建轻量级的、可控制的对象来代替为了编写测试为需要使用的对象。模拟对象还能够让你指定和测试你的代码与模拟对象本身之间的交互。
说的再直白一点,一个模拟对象就是一个简单的接口或者是类,在里面你可以定义一个特定的方法调用之后的简单的输出。
2.被测试的方法:
public class IncomeCalc {
private ICalcMethod method;
private Position position;
public void setMethod(ICalcMethod method) {
this.method = method;
}
public void setPosition(Position position) {
this.position = position;
}
public double calc(){
return method.calc(position);
}
}
接口:
public interface ICalcMethod {
public abstract double calc(Position position);
}
枚举类:
public enum Position {
BOSS,PROGRAMMER,MANAGER
}
3.使用JUnit和EasyMock进行测试:
import static org.junit.Assert.*;
import org.easymock.EasyMock;
import org.junit.Before;
import org.junit.Test;
public class IncomeCalcTest {
private ICalcMethod mock;
private IncomeCalc incomeCalc;
@Before
public void setUp() throws Exception {
//一、建立模拟对象
mock=EasyMock.createMock(ICalcMethod.class);
incomeCalc=new IncomeCalc();
}
/**
* expect方法告知EasyMock希望得到一个特定的方法,使用一些特定的参数,
* addReturn为某一个方法定义返回值。times方法定义了模拟对象将被调用几次。
* reply方法需要在让模拟对象可用之前被调用。
* 执行完测试之后,你可以调用verify方法来检查模拟对象是不是跟预期的一样被调用了。
*/
@Test
public void testCalc() {
//二、准备工作:记录:记录测试中所用到得方法、返回值和执行次数。
EasyMock.expect(mock.calc(Position.BOSS)).andReturn(7000.00).times(2);
EasyMock.expect(mock.calc(Position.MANAGER)).andReturn(5000.00);
//三、准备完后:设置mock对象为“回放”模式
EasyMock.replay(mock);
//四、进行测试
incomeCalc.setMethod(mock);
incomeCalc.setPosition(Position.BOSS);
assertEquals(7000.00, incomeCalc.calc());//因为预定测试2遍
assertEquals(7000.00, incomeCalc.calc());//否则会出错
incomeCalc.setPosition(Position.MANAGER);
assertEquals(5000.00, incomeCalc.calc());
//incomeCalc.setPosition(Position.PROGRAMMER);
//五、判断这个模拟对象中的所有的方法是否已经都执行了。
// 不是必需的步骤
EasyMock.verify(mock);
}
}
1.Failure
Failure指的是由于预期的结果与实际运行的测试的结果不同而导致的,例如当使用assertEquals()或其它assertXXX()方法断言失败时,就会报出Failure,如果发现Faulure,你就要去检查你的测试方法或者是被测试方法中编写的逻辑是否有误。
2.Error
Error指的是编写程序时没有考虑到的问题。在执行测试的断言之前,程序就因为某种类型的意外而停止,比喻说我们在操作数组的时候,因为存取超出索引会引发ArrayIndexOutOfBoundsException,这个时候程序就会报出Error,程序将无法运行下去,提前结束,这个时候你要检查被测试方法中是不是有欠缺考虑到地方。
3.测试代码:
package com.junit.test;
import static org.junit.Assert.*;
import org.junit.BeforeClass;
import org.junit.Test;
public class TestErrorFailure {
@BeforeClass
public static void setUpBeforeClass() throws Exception {
}
@Test
public void errorTest(){
int [] arr={1,2,3};
System.out.println("出现error:"+arr[4]);
}
@Test
public void failureTest(){
int [] arr={1,2,3};
assertEquals(3, arr[0]);
}
}
哪个先执行到,就先报哪个错误:
package com.junit.test;
import static org.junit.Assert.*;
import org.junit.BeforeClass;
import org.junit.Test;
public class TestErrorFailure {
@BeforeClass
public static void setUpBeforeClass() throws Exception {
}
//@Test
public void errorTest(){
int [] arr={1,2,3};
System.out.println("出现error:"+arr[4]);
}
@Test
public void failureTest(){
int [] arr={1,2,3};
System.out.println("出现error:"+arr[4]);
assertEquals(3, arr[0]);
}
}
4.Java中的Exception和Error:
Exception可以被人为的控制和处理,而Error不应该被认为的处理(如内存溢出,线程死锁)。
1.异常测试:
异常测试是 JUnit 4 中的最大改进。旧式的异常测试是在抛出异常的代码中放入 try 块,然后在 try 块的末尾加入一个 fail() 语句。例如,该方法测试被零除抛出一个 ArithmeticException:
public void testDivisionByZero() {
try {
int n = 2 / 0;
fail("Divided by zero!");
}
catch (ArithmeticException success) {
assertNotNull(success.getMessage());
}
}
该方法不仅难看,而且试图挑战代码覆盖工具,因为不管测试是通过还是失败,总有一些代码不被执行。在 JUnit 4 中,您现在可以编写抛出异常的代码,并使用注释来声明该异常是预期的:
@Test(expected=ArithmeticException.class)
public void divideByZero() {
int n = 2 / 0;
}
如果该异常没有抛出(或者抛出了一个不同的异常),那么测试就将失败。但是如果您想要测试异常的详细消息或其他属性,则仍然需要使用旧式的 try-catch 样式。
2. 可以忽略到测试:
也许您有一个测试运行的时间非常地长。不是说这个测试应该运行得更快,而是说它所做的工作从根本上比较复杂或缓慢。需要访问远程网络服务器的测试通常都属于这一类。如果您不在做可能会中断该类测试的事情,那么您可能想要跳过运行时间长的测试方法,以缩短编译-测试-调试周期。或者也许是一个因为超出您的控制范围的原因而失败的测试。例如,W3C XInclude 测试套件测试 Java 还不支持的一些 Unicode 编码的自动识别。不必老是被迫盯住那些红色波浪线,这类测试可以被注释为 @Ignore,如下所示:
// Java doesn't yet support
// the UTF-32BE and UTF32LE encodings
@Ignore public void testUTF32BE()
throws ParsingException, IOException, XIncludeException {
File input = new File("data/xinclude/input/UTF32BE.xml");
Document doc = builder.build(input);
Document result = XIncluder.resolve(doc);
Document expectedResult = builder.build(new File(outputDir, "UTF32BE.xml"));
assertEquals(expectedResult, result);
}
测试运行程序将不运行这些测试,但是它会指出这些测试被跳过了。
但是一定要小心。最初编写这些测试可能有一定的原因。如果永远忽略这些测试,那么它们期望测试的代码可能会中断,并且这样的中断可能不能被检测到。忽略测试只是一个权宜之计,不是任何问题的真正解决方案。
1.注解方法:
| Annotation | 含义 |
| @Test public void method() | 定义一个要测试的方法 |
| @Before public void method() | 在每一个测试之前都会被执行的方法,这个方法常常用来进行一 些测试环境的准备,比喻说读入输入数据,初始化类 |
| @After public void method() | 与@Before进行对应,做一个清理工作 |
| @BeforeClass public void method() | 在所有的测试开始之前执行,这个方法在类运行的时候运行, 而且只会运行一次,所以常常用来做一些所有的方法都要依赖 到工作,比喻说,数据库的链接。 |
| @AfterClass public void method() | 与@BeforeClass进行对应,做一些类级别的清理工作 |
| @Ignore | 表明方法是被忽略的,这个方法非常实用,比喻你的方法已经 修改,但是对应的测试方法还没有得到一致的修改的时候,可以 忽略掉这个测试方法先。 |
| @Test(expected=IllegalArgumentException.class) | 检查测试方法是不是抛出了对应的异常 |
| @Test(timeout=100) | 如果方法的执行操作所耗费的毫秒数>100MS,那么方法失败。 |
2.断言方法:

3.Before和After的简单测试:
package com.junit.demo;
public class MathDemo {
public int add(int a,int b){
return a+b;
}
public int div(int a,int b){
return a/b;
}
}JUnit测试:
package com.junit.test;
import static org.junit.Assert.*;
import java.util.logging.Logger;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import com.junit.demo.MathDemo;
public class MathDemoTest {
private MathDemo demo;
private Logger logger=Logger.getLogger(this.getClass().getName());
@Before
public void setUp() throws Exception {
logger.info("测试开始的准备");
demo=new MathDemo();
}
@After
public void tearDown() throws Exception {
logger.info("测试结束前的操作");
demo=null;
}
@Test
public void testAdd() {
int actual=demo.add(4, 5);
int expected=9;
assertEquals(expected, actual);
}
@Test
public void testDiv() {
int actual=demo.div(9, 3);
int expected=3;
assertEquals(expected, actual);
}
}
输出结果:
2009-7-27 10:47:55 com.junit.test.MathDemoTest setUp
信息: 测试开始的准备
2009-7-27 10:47:55 com.junit.test.MathDemoTest tearDown
信息: 测试结束前的操作
2009-7-27 10:47:55 com.junit.test.MathDemoTest setUp
信息: 测试开始的准备
2009-7-27 10:47:55 com.junit.test.MathDemoTest tearDown
信息: 测试结束前的操作
|
@Before public void method() |
在每一个测试之前都会被执行的方法,这个方法常常用来进行一
些测试环境的准备,比喻说读入输入数据,初始化类 |
|
@After public void method() |
与@Before进行对应,做一个清理工作 |