JUnit与JMock学习
测试驱动编程和持续集成部署应该说是现在软件开发者的必备武器,不过跟其他很多好东西一样,在我们公司的推广总要慢上一拍,毕竟老板看的是你能够把功能实现好让客户满意,所以能不折腾就不折腾。但不管用不用,先学下单元测试技术吧。
JUnit单元测试
用JUnit写单元测试,首先是定义一个单元测试类;然后在类中定义测试方法,使用@Test标签即可。
重要标签
ANNOTATION | DESCRIPTION |
---|---|
@Test | 定义test case |
@Test(expected = Exception.class) | 如果没有抛出某个异常则失败 |
@Test(timeout=100) | 如果超过多少毫秒则失败 |
@Before | 在每个test case前执行 |
@After | 在每个test case后执行 |
@BeforeClass | 在每个test class前执行 |
@AfterClass | 在每个test class执行 |
@Ignore | 忽略执行某个测试方法 |
运行多个测试集
可以定义一个测试集来依次运行多个测试类
1 package com.vogella.junit.first; 2 3 import org.junit.runner.RunWith; 4 import org.junit.runners.Suite; 5 import org.junit.runners.Suite.SuiteClasses; 6 7 @RunWith(Suite.class) 8 @SuiteClasses({ MyClassTest.class, MySecondClassTest.class }) 9 public class AllTests { 10 11 }
JMockit使用
单元测试一般只测试某一个功能,但是由于类之间的耦合性往往难以把功能隔离开来。例如你希望测试某个业务逻辑处理数据的功能,但是数据是从Database取回的,这就涉及到DAO层的类调用;你不希望单元测试函数去访问数据库(除非是测试DAO的单元测试),于是你希望有一个假的DAO类刚好返回你需要的测试数据。Mock的作用就是在单元测试里模拟类的行为和状态。市面上有好几种Mock库,包括EasyMock, Mockit等,这里我还是推荐功能更加强大的JMockit库。
JMockit有好几种不同的使用方式,但基本的思路相同。第一就是需要用到哪些Mock类或者方法,就定义多少,绝不Mock无用的类和方法。第二在编写程序时候就需要尽量使得类之间的调用接口化。
第一种是所谓的"State-oriented mocking",也就是基于状态的模拟,有个例子:
1 package com.test; 2 3 import mockit.MockUp; 4 5 import org.junit.Test; 6 import junit.framework.TestCase; 7 8 /** 9 * 类名: 10 * 类说明: 11 * 12 * @version V1.0 13 * @author lu7kang 2011-3-31 14 */ 15 public class MyTestCase extends TestCase { 16 17 @Test 18 public void test() throws Exception{ 19 // mock第三方接口方法-返回成功 20 MockUp mu3 = new MockUp() { 21 @Mock 22 public EFaxResult updateNumberProfile(NumberProfile numberProfile, String memberId) { 23 EFaxResult rst = new EFaxResult(); 24 // mock第三方方法-返回成功100 25 rst.setResultCode(ResultCode.RC_100); 26 return rst; 27 } 28 }; 29 // 测试本地代码 30 MyService myservice = new MyServiceImpl(); 31 NumberProfile numberProfile = new NumberProfile(); 32 String memberId = "test_id"; 33 // 测试自己的方法 34 rst = myservice.doMyNumberProfile(numberProfile, memberId); 35 Assert.assertEquals(ResultCode.RC_100, rst.getResultCode()); 36 } 37 }
在MyService的实现里用到了ESPService的updateNumberProfile方法,于是测试中通过创建一个new MockUp()类(并实现updateNumberProfile方法),可以让JMockit在单元测试运行过程中用Mock的updateNumberProfile代替原生的调用。
还有一种Behavior Based使用方法,其定义mock的方式就是先录制好某些方法调用和返回结果。例如:
1 2 @Mocked T mock1; // all current and future instances are mocked 3 @Injectable K anotherMock; // only one particular instance is mocked 4 5 @Test 6 public void aTestMethod() 7 { 8 new NonStrictExpectations() {{ 9 mock1.getData(); result = "my test data"; 10 anotherMock.doSomething(anyInt, "some expected value", anyString); times = 1; 11 }}; 12 13 // In the replay phase, the tested method would call the "getData" and "doSomething" 14 // methods on a "MyCollaborator" instance. 15 ... 16 17 // In the verify phase, we may optionally verify expected invocations to "MyCollaborator" 18 // objects. 19 ... 20 }