zoukankan      html  css  js  c++  java
  • 单元测试-Junit-Mockit-PowerMock

    0. Junit5

    1. Junit4

    //手动命令行测试
    java -cp /usr1/junit:/usr1/cdncms/lib/* org.junit.runner.JUnitCore com.test.DomainServiceTest
    
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
      <scope>test</scope>
    </dependency>
    

    1.0 执行报错java.lang.VerifyError: Expecting a stackmap frame at branch target 122

    增加配置项: windsows-->installJREs-->edit -->  VM arguments --> 增加 -noverify
    

    1.1 Junit注解

    @BeforeClass 针对所有测试,只执行一次,且必须为static void
    @Before: 初始化方法
    @Test: 测试方法,在这里可以测试期望异常和超时时间
    @After: 释放资源
    @AfterClass: 针对所有测试,只执行一次,且必须为static void
    @Ignore: 忽略的测试方法

    一个单元测试用例执行顺序为: @BeforeClass –> @Before –> @Test –> @After –> @AfterClass
    每一个测试方法的调用顺序为: @Before –> @Test –> @After

    1.2 Assert类

    assertEquals(boolean expected, boolean actual)	检查两个变量或者等式是否平衡
    assertFalse(boolean condition)		检查条件是假的
    assertNotNull(Object object)	检查对象不是空的
    assertNull(Object object)	检查对象是空的
    assertTrue(boolean condition)	检查条件为真
    fail()	在没有报告的情况下使测试不通过
    

    junit匹配抛出异常

        @Test(expected = IllegalArgumentException.class)
        public void canVote_throws_IllegalArgumentException_for_zero_age() {.......}
    

    2. Mockito--创建 Mock 对象并且定义它的行为

    2.1

    a). 静态方法: import static org.mockito.Mockito.*;
    b). 验证方法是否调用: verify(test, times(2)).getUniqueId();
    

    2.2 示例

    基本用法: (无法对static method和private method进行插桩)
                    when(cls.methodName(args)).thenReturn(args)	//对指定语句进行插桩
                    when(cls.methodName(args)).thenThrow(Exception)	//抛出异常
    
    1、 基本示例
                    LinkedList mockedList = mock(LinkedList.class);
    
                    //插桩
                    when(mockedList.get(0)).thenReturn("first");
                    when(mockedList.get(1)).thenThrow(new RuntimeException());
    
                    System.out.println(mockedList.get(0));	//输出"first"
    
                    System.out.println(mockedList.get(1));	//抛出异常
    
                    System.out.println(mockedList.get(999));	//输出 null , 因为get(999)未插桩
    
    
    2、 插桩时可用 Matcher.anyString()/anyInt() 等进行入参匹配
                    when(mockedList.get(anyInt())).thenReturn("element");
    
    
    3、 针对void方法抛出异常
                    doThrow(new RuntimeException()).when(mockedList).clear();
    
    4、 针对void方法插桩
                    doNothing().when(spy).clear();
    

    3. PowerMock--插桩,static/final/private

    3.1 原理

    //两个重要注解 -- 使用ASM生成代理类进行mock
    	 @RunWith(PowerMockRunner.class)	//通用配置
    	 @PrepareForTest( { YourClassWithEgStaticMethod.class })	//需要powermock处理的class,static、final、私有方法等功能
     1) 例如:去除'final方法的final标识,在静态方法的最前面加入自己的虚拟实现等。
     2) 如果mock的是系统类的final/static,PowerMock会修改调用系统类的class文件,以满足mock需求。
     
     	<properties>
    		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    		<powermock.version>1.7.1</powermock.version>
    	</properties>
    
    	<dependencies>
    		<dependency>
    			<groupId>org.powermock</groupId>
    			<artifactId>powermock-module-junit4</artifactId>
    			<version>${powermock.version}</version>
    			<scope>test</scope>
    		</dependency>
    		<dependency>
    			<groupId>org.powermock</groupId>
    			<artifactId>powermock-api-mockito</artifactId>
    			<version>${powermock.version}</version>
    			<scope>test</scope>
    		</dependency>
    	</dependencies>
    
    //通过PowerMock创建一个虚拟对象
    InterfaceToMock mock = Powermockito.mock(InterfaceToMock.class)
    
    //value为你想要让这个method返回的值
    Powermockito.when(mock.method(Params…)).thenReturn(valueToReturn)
    
    //如果这个方法返回值为空,则上面的写法会报错,可采用下面的写法
    Powermockito.when(mock, “methodName”, Object… params).thenReturn(valueToReturn)
    
    // 也可以采用下面的写法,和上面的一样的效果
    Powermockito.doReturn(valueToReturn).when(mock, “methodName”, Object… params)
    
    //这样写也行,适合返回值为void的方法
    Powermockito.doReturn(valueToReturn).when(mock).methodName(Object… params)
    
    //你也可以让方法抛异常
    Powermockito.when(mock.method(Params..)).thenThrow(new OMSException(“oms”))
    
    //你可以让方法每一次返回的结果都不一样,下面的例子第一次正常返回,第二次调用抛异常
    Powermockito.when(mock.method(Params..)).thenReturn(valueToReturn).thenThrow(new OMSException(“some Exception”))
    
    //如果方法返回值为void,不能用thenReturn,要用doThing()
    Powermockito.doNothing().when(mock.method(Params…))
    

    3.2 示例1-mock static方法

    public class IdGenerator {
      public static long generateNewId() { 
        return 0L;
      } 
    }
    
    public class ClassUnderTest {
        public long methodToTest() { 
              final long id = IdGenerator.generateNewId(); 
              return id;
        } 
    }
    
    @RunWith(PowerMockRunner.class)
    @PrepareForTest(IdGenerator.class)
    public class TestStatic {
        @Test
        public void testCallInternalInstance() throws Exception {
              PowerMockito.mockStatic(IdGenerator.class);
              // 在这个测试用例中,当generateNewId()每次被调用时,都会返回15
              PowerMockito.when(IdGenerator.generateNewId()).thenReturn(15L);
              Assert.assertEquals(15L, new ClassUnderTest().methodToTest());
      }
    }
    

    3.2 示例2-模拟构造方法

    public class ClassUnderTest {
          public boolean createDirectoryStructure(String directoryPath) {
                File directory = new File(directoryPath);
                if (directory.exists()) {
                      String msg = """ + directoryPath + "" 已经存在.";
                      throw new IllegalArgumentException(msg);
                }
                return directory.mkdirs();
          }
    }
    
    @RunWith(PowerMockRunner.class) 
    @PrepareForTest(ClassUnderTest.class) 
    public class TestConstruction { 
        //模拟构造函数
        @Test 
        public void createDirectoryStructureWhenPathDoesntExist() throws Exception { 
                final String directoryPath = "seemygod"; 
                //创建File的模拟对象
                File directoryMock = mock(File.class); 
                //在当前测试用例下,当出现new File("seemygod")时,就返回模拟对象
                whenNew(File.class).withArguments(directoryPath).thenReturn(directoryMock); 
                //当调用模拟对象的exists时,返回false
                when(directoryMock.exists()).thenReturn(false); 
                //当调用模拟对象的mkdirs时,返回true
                when(directoryMock.mkdirs()).thenReturn(true); 
                assertTrue(new ClassUnderTest().createDirectoryStructure(directoryPath)); 
                //验证new File(directoryPath);  是否被调用过
                verifyNew(File.class).withArguments(directoryPath); 
        } 
    }
    

    3.4 用例3-模拟私有以及 Final 方法

    public class PrivatePartialMockingExample {
        public String methodToTest() {
                return methodToMock("input");
        }
        private String methodToMock(String input) {
                return "REAL VALUE = " + input;
        }
    }
    
    import static org.powermock.api.mockito.PowerMockito.*;
    @RunWith(PowerMockRunner.class)
    @PrepareForTest(PrivatePartialMockingExample.class)
    public class PrivatePartialMockingExampleTest {
        @Test
        public void demoPrivateMethodMocking() throws Exception {
                final String expected = "TEST VALUE";
                final String nameOfMethodToMock = "methodToMock";
                final String input = "input";
                PrivatePartialMockingExample underTest = spy(new PrivatePartialMockingExample());
                //模拟私有方法
    			when(underTest, nameOfMethodToMock, input).thenReturn(expected);
                assertEquals(expected, underTest.methodToTest());
                verifyPrivate(underTest).invoke(nameOfMethodToMock, input);
        }
    }
    

    3.5 用例4-mock系统类的静态和final方法

    public class ClassUnderTest {
        public boolean callSystemFinalMethod(String str) { 
            return str.isEmpty();  
        }  
        public String callSystemStaticMethod(String str) { 
            return System.getProperty(str);  
        }
    }
    
    $RunWith(PowerMockRunner.class)  
    public class TestClassUnderTest {
       $Test  
       $PrepareForTest(ClassUnderTest.class)  
       public void testCallSystemStaticMethod() {  
          ClassUnderTest underTest = new ClassUnderTest();  
    
          PowerMockito.mockStatic(System.class);  
    
          PowerMockito.when(System.getProperty("aaa")).thenReturn("bbb");
      
          Assert.assertEquals("bbb", underTest.callJDKStaticMethod("aaa"));  
      }  
    }
    

    3.6 用例-PowerMock处理注解

    //PushMsgPostProcessorImpl 是要测试的类,它有两个注解注入的类变量如下:
    	@Resource
    	 private IMsgToUserService msgToUserService;
    //则测试类中可以使用下面的方法注入
    	@Mock
    	 private IMsgToUserService msgToUserService;
    	 @Before
    	 public void setup() {
    	  MockitoAnnotations.initMocks(this);
    	  pushMsgPostProcessor = new PushMsgPostProcessorImpl();
    	  //给注解的private变量塞一个值
    	  ReflectionTestUtils.setField(pushMsgPostProcessor, "msgToUserService", msgToUserService);
    	 }
    

    3.10 模拟异常

    3.10.1 抛出异常-不带参数

    //PowerMockito.when(IOUtils.xMLReader()).thenThrow(SAXException.class);
    public class IOUtils {
    	public static String xMLReader() throws SAXException {
    		return "abc";
    	}
    }
    

    3.10.2 抛出异常-待参数的异常

    //PowerMockito.doThrow(new SAXException()).when(IOUtils.class);
    public class IOUtils {
    	public static String xMLReader(SAXReader reader) throws SAXException {
    		System.out.println("IOUtils.xMLReader");
    		if (null == reader) {
    			throw new SAXException();
    		}
    		return "abc";
    	}
    }
    
  • 相关阅读:
    [Docker][ansible-playbook]3 持续集成环境之分布式部署
    [Jenkins][GitHub]2 持续集成环境初探
    [Jenkins][centos]1 持续集成 之 配置VNC,部署Jenkins
    [AWS][GUI][VNC]rhel 7 安装GUI ,配置VNC
    [Git]checkout 指定版本
    [Golang][Mac]Go 语言学习资料记录
    App测试札记
    摘记:代码检查错误列表
    摘记:Web应用系统测试内容
    摘记:LoadRunner
  • 原文地址:https://www.cnblogs.com/Desneo/p/7674750.html
Copyright © 2011-2022 走看看