原文地址:http://www.vogella.de/articles/JUnit/article.html
本文地址:博客园 逖靖寒 http://gpcuster.cnblogs.com
译文:
这篇文章简单讲解了如何在Eclipse中利用Junit 4.x和EasyMock进行单元测试。
当你阅读完这篇文章后,可以在Eclipse中使用JUnit进行单元测试。
单元测试开发人员写的用于测试某一个功能的代码。单元测试可以保证程序的功能正常使用。
JUnit 4.x 是一个自动化测试的框架,最初的作者是Erich Gamma and Kent Beck。它使用Java的annotation特性来标记出需要进行测试的方法。
在JUnit中,有一个非常重要的约定:所有的测试用例都不应该依赖于其他的测试用例。
下载JUnit4.x.jar可以去JUnit的官网here ,并且将其添加到classpath中。
现在的Eclipse版本中已经整合了Junit,你可以直接使用。
JUnit 使用annotations来区别需要进行测试的方法。
编写一个测试用例:
给需要测试的方法加上annotations:@org.JUnit.Test
如果你希望检测2个对象是否相等,使用org.JUnit.Assert.*,并调用assertEquals()。
Static imports在Java 5.0或以上版本是有效的,如:import static org.junit.Assert.*
编写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); } }
在Eclipse的菜单栏中选择:Run As -> JUnit test
Eclipse将通过绿色和红色的状态栏显示运行的结果。
创建一个全新的项目"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"。
创建一个包 "gpcuster.cnblog.com"。
在包 "gpcuster.cnblog.com"中创建一个类"MyClass" 代码如下:
package gpcuster.cnblogs.com; public class MyClass { public int multiply(int x, int y) { return x / y; } }
选中你需要测试的类,然后操作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。
测试结果如图所示,你可以修改代码中存在的问题,然后再次运行。如果成功,将看到绿色的状态栏。
如果需要测试的用例很多,我们可以创建一个测试集,包含所有需要进行测试的测试用例。
选项需要测试的类,然后鼠标右击: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 { }
对于每一个测试用例,你都可以实现setUp()和tearDown(). setUp在每一个测试用例初始化的时候被调用。tearDown()在每一个测试用例结束的时候被调用。
Junit中大量使用了static方法。
Eclipse无法自动导入static imports。
你需要做的是将'org.junit.Assert'导入到Java > Editor > Content Assist > Favorites中。当你这么做了以后,你可以使用Content Assist (Ctrl+Space) 来添加方法。
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
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语句
我们的上一个示例非常简单,但是在实际的环境中,我们的需要测试的类可能会依赖与其他的第三方库。
所以,测试我们的类需要去模拟或者是控制其他的第三方库。最佳的处理方案应该是创建一个mock对象。mock对象可以手工编写产生也可以通过使用EasyMock来产生。
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对象是否被调用了。
原文地址:http://www.vogella.de/articles/JUnit/article.html
本文地址:博客园 逖靖寒 http://gpcuster.cnblogs.com