LLT是测试系统的一部分,主要是由代码开发人员来编写,Mock的意思是效仿模仿的意思,就是最测试过程中不需要的一些类和方法模拟出相应的返回值,称为打桩,测试关注的是一个类或方法的结果而不是过程调用,打桩涉及到不同的类,有返回值、无返回值、参数验证、静态类静态方法、final方法等不同的方式。
流行的Mock工具如jMock、EsayMock、Mockito等不能mock静态、final、私有方法
PowerMock中的注释
1. 程序运行顺序注释
1)Test将一个普通的方法装饰成为一个测试方法
2)@BeforeClass 它会在所有的方法运行之前进行执行,static修饰
3)@AfterClass 它会在所有的方法运行结束之后进行执行,static修饰
4)@Before 会在每个测试方法运行之前执行一次
5)@After 会在每个测试方法运行之后执行一次
其中@Before @Test @After 这三个标签是组成执行的。有几个@Test,就会执行多少次。
2. 其他运行注解
1)@RunWith 可以修改测试运行期 org.junit.runner.Runner,当需要mock私有方法调用的私有方法是,需要加上@RunWith(PowerMockRunner.class)
2)@PrepareForTest 在使用mock是,首先要在该项添加mock的类@PrepareForTest({类名.class})
@PrepareForTest 注解和@RunWith注解是结合使用的,不要用单独使用它们中的任何一个,否则不起作用,当使用PowerMock和去mock静态,final或者私有方法时,需要机上两个注解。
常用的Mock方法:
1.Mock普通对象(有返回值)
1 public class Calculator{ 2 public int Add(int a, int b){ 3 return a + b; 4 } 5 }
Mock方法如下(这里不需要添加PrepareForTest 和RunWith注解)
1 @Test 2 public void testAdd(){ 3 Calculator calculator = PowerMockito.mock(Calculator.class); 4 PowerMockito.when(calculator.Add(Mockito.anyInt(), Mockito.anyInt())).thenReturn(10); 5 assertEquals(10, calculator.Add(1, 1)); 6 }
2. Mock普通对象(无返回值)
1 public class Calculator{ 2 public void print(){ 3 System.out.println("Hello World"); 4 } 5 }
Mock方法如下(这里不需要添加PrepareForTest 和RunWith注解)
1 @Test 2 public void testPrint(){ 3 Calculator calculator = PowerMockito.mock(Calculator.class); 4 PowerMockito.doNothing().when(calculator).print(); 5 calculator.print(); 6 //验证Mock对象被调用 7 Mockito.verify(calculator).print(); 8 }
3. Mock静态方法
1 public class ClassThatContainsStaticMethod(){ 2 public static String getUserName(int id){ 3 String string = "UserName" + id; 4 return string; 5 } 6 }
Mock方法如下(这里不需要添加PrepareForTest 和RunWith注解)
1 @RunWith(PowerMockito.class) 2 @PreparaForTest(ClassThatContainsStaticMethod.class) 3 pulic class testClassThatContainsstaticMethod{ 4 @Test 5 public void testGetUserName() throws Exception{ 6 PowerMockito.mockStatic(ClassThatContainsStaticMethod.class); 7 PowerMockito.when(ClassThatContainsStaticMethod.getUserName(Mockito.anyInt())).thenReturn(null); 8 assertEquals(ClassThatContainsStaticMethod.getUserName(123), null); 9 } 10 }
4. Mock私有方法
使用PowerMockito.method获取Method对象调用私有方法,除此之外,还有Whitebox.InvokeMethod直接调用,在此不做说明;
1 public class Calculator{ 2 private int addPrivate(int a, int b){ 3 return a + b; 4 } 5 }
Mock方法如下:
1 @Test 2 public void testAddPrivate() throws Exception{ 3 Calculator calculator = PowerMockito.mock(Calculator.class); 4 PowerMockito.when(calculator, "addPrivate", Mockito.anyInt(), Mockito.anyInt).thenReturn(10); 5 6 Method method = PowerMockito.method(Calculator.class, "addPrivate", int.class, int.class); 7 int result = (Integer) method.invoke(calculator, 1,1); 8 assertEquals(10, result) 9 }
5. Mock final类或者方法
1 public final class Calculator{ 2 public final int add(int a, int b){ 3 return a + b; 4 } 5 public final void addVoid(int a, int b){ 6 System.out.println(a + b); 7 } 8 }
Mock方法如下:
1 @RunWith(PowerMockito.class) 2 @PreparaForTest(Calculator.class) 3 public class CalculatorTest{ 4 @Test 5 public void testAdd(){ 6 Calculator calculator PowerMockito.mock(Calculator.class); 7 PowerMockito.when(calculator.add(Mockito.anyInt(), Mockito.anyInt())).thenReturn(10); 8 int result = calculator.add(1,1); 9 assertEquals(result, 10); 10 } 11 @Test 12 public void testAddVoid(){ 13 Calculator calculator = PowerMockito.mock(Calculator.class); 14 PowerMockito.doNothing().when(calculator).addVoid(Mockito.anyInt(), Mockito.anyInt()); 15 calculator.addVoid(100,100); 16 Mockito.verify(calculator).addVoid(100,100); 17 } 18 }
6. Mock构造函数
类一:
1 public class ClassUnderTest(){ 2 public boolean callFinalMethod(){ 3 ClassDependency classDependency = new ClassDependency(); 4 return classDependency.isAlive(); 5 } 6 }
类二:
1 public class ClassDependency{ 2 public final boolean isAlive(){ 3 return false; 4 } 5 }
Mock方法如下(whenNew创建对象是若不成功(如无对应构造函数))会抛出异常,讲义在test块抛出异常而不是用try。。。catch捕获,这样方便问题定位。
@RunWith(PowerMockito.class) @PreparaForTest({ClassUnderTest.class, ClassDependency.class}) public class TestClassUnderTest{ @Test public void testCallFinalMethod() throws Exception{ ClassDependency dependency = PowerMockito.mock(ClassDependency.class); //该项创建可能会抛出异常 PowerMockito.whenNew(ClassDependency.class).withNoArguments().thenReturn(dependency); ClassUnderTest classUnderTest = new ClassUnderTest(); Assert.assertEquals(classUnderTest.callFinalMethod()); } }
7. 反射设置变量的值
该方法主要是使用WhiteBox的setInternalState方法对变量在某个类中进行替代,模块中代码中经常用该方法mock掉数据库查询的操作。用本地化的mock数据库操作(如查询map对象替代)
public class ReflectObject{ private String privateStr = "str"; protected String protectedStr = "str"; private static String staticStr = "str"; public String getPrivateStr(){ return privateStr; } public String getProtectedStr(){ return protectedStr; } public static String getStaticStr(){ return staticStr; } }
Mock方法如下:
1 public class ReflectObjectTest(){ 2 @Test 3 public void testReflect() throws Exception{ 4 ReflectObject reflect = new ReflectObject(); 5 WhiteBox.setInternalState(reflect, "privateStr", "privateStr"); 6 WhiteBox.setInternalState(reflect, "protectedStr", "protectedStr"); 7 WhiteBox.setInternalState(reflect, "staticStr", "staticStr"); 8 9 assertEquals("privateStr", reflect.getPrivateStr()); 10 assertEquals("protectedStr", reflect.getProtectedStr()); 11 assertEquals("staticStr", reflect.getStaticStr()); 12 } 13 }
8. Mock静态方法抛异常
1 public class ThrowsException{ 2 public static void throwsException() throws RuntimeException{ 3 //do nothing 4 } 5 }
Mock方法如下:
public class ThrowsException{ @Test(expected=RuntimeException.class) public void testThrowsException(){ PowerMockito.mockStatic(ThrowsException.class); PowerMockito.doThrows(new RuntimeException("Test exception")).when(ThrowsException); ThrowsException.throwsException(); } }