在Eclipse中使用Junit4.x与EasyMock进行单元测试

摘要

这篇文章简单讲解了如何在Eclipse中利用Junit 4.x和EasyMock进行单元测试。

当你阅读完这篇文章后,可以在Eclipse中使用JUnit进行单元测试。


1. 概要

1.1. 单元测试

单元测试开发人员写的用于测试某一个功能的代码。单元测试可以保证程序的功能正常使用。

JUnit 4.x 是一个自动化测试的框架,最初的作者是Erich Gamma and Kent Beck。它使用Java的annotation特性来标记出需要进行测试的方法。

在JUnit中,有一个非常重要的约定:所有的测试用例都不应该依赖于其他的测试用例。

1.2. 安装

下载JUnit4.x.jar可以去JUnit的官网here,并且将其添加到classpath中。

现在的Eclipse版本中已经整合了Junit,你可以直接使用。

2. 如何编写单元测试

2.1. 概览

JUnit 使用annotations来区别需要进行测试的方法。

编写一个测试用例:

  • 给需要测试的方法加上annotations:@org.JUnit.Test

  • 如果你希望检测2个对象是否相等,使用org.JUnit.Assert.*,并调用assertEquals()。

Static imports在Java 5.0或以上版本是有效的,如:import static org.junit.Assert.*

2.2. 编写你的第一个单元测试

编写Java代码:

package gpcuster.cnblogs.com;

import static org.junit.Assert.assertEquals;

import org.junit.Test;

public class MyFirstJUnitTest {

    @Test
    public void simpleAdd() {
        int result = 1;
        int expected = 1;
        assertEquals(result, expected);
    }
}

2.3. 在Eclipse中运行你的单元测试

在Eclipse的菜单栏中选择:Run As -> JUnit test

Eclipse将通过绿色和红色的状态栏显示运行的结果。

3. 在Eclipse中使用JUnit

3.1. 准备

创建一个全新的项目"de.vogella.junit.junittest"。添加一个lib目录,将junit4.jar添加到classpath中,如果希望知道如何添加classpath,其查看Adding an external library to the Java classpath in Eclipse

接着创建一个test的源代码文件夹,如下图所示:

点击"Add folder",然后点击"Create new folder"。创建一个新的文件目录"test"。

3.2. 创建一个需要测试的类

创建一个包 "gpcuster.cnblog.com"。

在包 "gpcuster.cnblog.com"中创建一个类"MyClass" 代码如下:   

package gpcuster.cnblogs.com;

public class MyClass {
    public int multiply(int x, int y) {
        return x / y;
    }
}

3.3. 创建一个测试类

选中你需要测试的类,然后操作New ->JUnit Test case,再选择"New JUnit 4 test":

如果你还没有将JUnit放到你的classpath中,Eclipse将询问你是否将其加入classpath中:

测试类的代码如下:    

import static org.junit.Assert.assertEquals;

import org.junit.Test;

public class MyClassTest {

    @Test
    public void testMultiply() {
        MyClass tester = new MyClass();
        assertEquals("Result", 50, tester.multiply(10, 5));

    }
}

鼠标右击测试类,然后选择Run-As-> Junit Test。

测试结果如图所示,你可以修改代码中存在的问题,然后再次运行。如果成功,将看到绿色的状态栏。

3.4. 创建测试集

如果需要测试的用例很多,我们可以创建一个测试集,包含所有需要进行测试的测试用例。

选项需要测试的类,然后鼠标右击:New-> Other -> JUnit -Test Suite

创建的代码如下:

package gpcuster.cnblogs.com;

import org.junit.runner.RunWith;
import org.junit.runners.Suite;

@RunWith(Suite.class)
@Suite.SuiteClasses( { MyClassTest.class })
public class AllTests {
}

4. 进一步了解JUnit

4.1. setUp()与tearDown()

对于每一个测试用例,你都可以实现setUp()和tearDown(). setUp在每一个测试用例初始化的时候被调用。tearDown()在每一个测试用例结束的时候被调用。

4.2. 在Eclipse中使用Static imports

Junit中大量使用了static方法。

Eclipse无法自动导入static imports。

你需要做的是将'org.junit.Assert'导入到Java > Editor > Content Assist > Favorites中。当你这么做了以后,你可以使用Content Assist (Ctrl+Space) 来添加方法。

4.3. Annotations

JUnit 4.x中Annotations的使用如下:

Annotation描述

@Test public void method()

需要被测试的方法。

@Before public void method()

在每一个测试用例执行前,需要调用的方法。

@After public void method()

在每一个测试用例执行后,需要调用的方法。

@BeforeClass public void method()

所有测试用例执行前,需要调用的方法。

@AfterClass public void method()

所有测试用例执行后,需要调用的方法。

@Ignore

忽略该测试的方法。

@Test(expected=IllegalArgumentException.class)

期望测试用例抛出指定的异常。

@Test(timeout=100)

测试用例期望的执行时间。

表1. Annotations

4.4. Assert语句

JUnit 4.x中Assert语句的使用如下:

Assert语句描述

fail(String)

方法失败。

assertTrue(true)

检测是否为真。

assertsEquals([String message], expected, actual)

检测2个对象是否相等

assertsEquals([String message], expected, actual, tolerance)

检测2个对象在允许的精度范围内是否相等。

assertNull([message], object)

检测是否为空。

assertNotNull([message], object)

检测是否为非空。

assertSame([String], expected, actual)

检测2个对象是否是为一个对象。

assertNotSame([String], expected, actual)

检测2个对象是否是为非一个对象。

assertTrue([message], boolean condition)

检测是否为真。

try {a.shouldThroughException(); fail("Failed")} catch (RuntimeException e) {asserttrue(true);}

检测是否抛出异常。

表2. Assert语句

5. Easy Mock

5.1. Easy Mock 概要

我们的上一个示例非常简单,但是在实际的环境中,我们的需要测试的类可能会依赖与其他的第三方库。

所以,测试我们的类需要去模拟或者是控制其他的第三方库。最佳的处理方案应该是创建一个mock对象。mock对象可以手工编写产生也可以通过使用EasyMock来产生。

mock对象是一个空的接口,你可以完全控制实现接口的对象的所有行为。

5.2. Using Junit and Easy Mock

下载EasyMock,将easymock.jar添加到你的classpath中。

创建一个Java Project JavaMockTest。 同时创建下面代码中的这些类。 IncomeCalculator需要被测试。

package income;

public enum Position {
    BOSS, PROGRAMMER, SURFER
}

                            
package income.exceptions;

public class PositionException extends RuntimeException {

    private static final long serialVersionUID = 1L;

    public PositionException(String message) {
        super(message);
    }
}

                            
package income.exceptions;

public class CalcMethodException extends RuntimeException {

    private static final long serialVersionUID = 1L;

    public CalcMethodException(String message) {
        super(message);
    }
}

                            
package income.method;

import income.Position;

public interface ICalcMethod {

    public abstract double calc(Position position);

}
                            
package income;

import income.exceptions.CalcMethodException;
import income.exceptions.PositionException;
import income.method.ICalcMethod;


public class IncomeCalculator{
    
    private ICalcMethod calcMethod;
    private Position position;

    public void setCalcMethod(ICalcMethod calcMethod){
        this.calcMethod = calcMethod;
    }
    public void setPosition(Position position){
        this.position = position;
    }
    public double calc (){
        if (calcMethod==null){
            throw new CalcMethodException("CalcMethod not yet maintained");
        }
        if (position==null){
            throw new PositionException("Position not yet maintained");
        }
        return calcMethod.calc(position);
    }
}

我们在JUnit中使用EasyMock来进行测试:

package income;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import income.exceptions.CalcMethodException;
import income.exceptions.PositionException;
import income.method.ICalcMethod;

import org.easymock.EasyMock;
import org.junit.Before;
import org.junit.Test;

public class IncomeCalculatorTest {

    private ICalcMethod calcMethod;
    private IncomeCalculator calc;

    @Before
    public void setUp() throws Exception {
        calcMethod = EasyMock.createMock(ICalcMethod.class);
        calc = new IncomeCalculator();
    }

    @Test
    public void testCalc1() {
        // Setting up the expected value of the method call calc
        EasyMock.expect(calcMethod.calc(Position.BOSS)).andReturn(70000.0)
                .times(2);
        EasyMock.expect(calcMethod.calc(Position.PROGRAMMER))
                .andReturn(50000.0);
        // Setup is finished need to activate the mock
        EasyMock.replay(calcMethod);

        calc.setCalcMethod(calcMethod);
        try {
            calc.calc();
            fail("Exception did not occur");
        } catch (PositionException e) {

        }
        calc.setPosition(Position.BOSS);
        assertEquals(70000.0, calc.calc());
        assertEquals(70000.0, calc.calc());
        calc.setPosition(Position.PROGRAMMER);
        assertEquals(50000.0, calc.calc());
        calc.setPosition(Position.SURFER);
        EasyMock.verify(calcMethod);
    }

    @Test(expected = CalcMethodException.class)
    public void testNoCalc() {
        calc.setPosition(Position.SURFER);
        calc.calc();
    }

    @Test(expected = PositionException.class)
    public void testNoPosition() {
        EasyMock.expect(calcMethod.calc(Position.BOSS)).andReturn(70000.0);
        EasyMock.replay(calcMethod);
        calc.setCalcMethod(calcMethod);
        calc.calc();
    }

    @Test(expected = PositionException.class)
    public void testCalc2() {
        // Setting up the expected value of the method call calc
        EasyMock.expect(calcMethod.calc(Position.SURFER)).andThrow(
                new PositionException("Don't know this guy")).times(1);

        // Setup is finished need to activate the mock
        EasyMock.replay(calcMethod);
        calc.setPosition(Position.SURFER);
        calc.setCalcMethod(calcMethod);
        calc.calc();
    }

}

expect方法告诉我们的Mock对象如果针对特殊的参数返回特定的值。

我们需要调用reply方法使我们的Mock对象有效。

当调用结束的时候,你可以调用verify的方法来检查Mock对象是否被调用了。



  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值