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";
}
}