單元測試-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: 忽略的測試方法html

一個單元測試用例執行順序爲: @BeforeClass –> @Before –> @Test –> @After –> @AfterClass
每個測試方法的調用順序爲: @Before –> @Test –> @Afterjava

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) //拋出異常

一、 基本示例
                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)未插樁


二、 插樁時可用 Matcher.anyString()/anyInt() 等進行入參匹配
                when(mockedList.get(anyInt())).thenReturn("element");


三、 針對void方法拋出異常
                doThrow(new RuntimeException()).when(mockedList).clear();

四、 針對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";
    }
}
相關文章
相關標籤/搜索