➜ Old React website
Chung Cheuk Hang MichaelJava Web Developer
Java 測試(五):WireMock透過 Redis CLI 學習 Redis

Java 測試(四):PowerMock

Continued from previous post:
Java 測試(一):簡介

Table of contents

4 PowerMock

JDK 版本方面,8 或者 11 都可以。

4.1 Maven dependencies

因為 PowerMock 同 Mockito 既一啲兼容性問題,我地一定要用 Mockito 3.9.0,唔可以用 4.0.0 或者以上既版本。
1<properties> 2 <powermock.version>2.0.9</powermock.version> 3</properties> 4 5<dependencyManagement> 6 <dependencies> 7 <dependency> 8 <groupId>org.springframework.boot</groupId> 9 <artifactId>spring-boot-dependencies</artifactId> 10 <version>2.7.1</version> 11 <type>pom</type> 12 <scope>import</scope> 13 </dependency> 14 </dependencies> 15</dependencyManagement> 16 17<dependencies> 18 <dependency> 19 <groupId>org.springframework.boot</groupId> 20 <artifactId>spring-boot-starter-web</artifactId> 21 </dependency> 22 23 <dependency> 24 <groupId>org.apache.commons</groupId> 25 <artifactId>commons-lang3</artifactId> 26 </dependency> 27 28 <dependency> 29 <groupId>org.springframework.boot</groupId> 30 <artifactId>spring-boot-starter-test</artifactId> 31 <scope>test</scope> 32 </dependency> 33 34 <dependency> 35 <groupId>org.junit.vintage</groupId> 36 <artifactId>junit-vintage-engine</artifactId> 37 <scope>test</scope> 38 </dependency> 39 40 <dependency> 41 <groupId>org.powermock</groupId> 42 <artifactId>powermock-module-junit4</artifactId> 43 <version>${powermock.version}</version> 44 <scope>test</scope> 45 </dependency> 46 47 <dependency> 48 <groupId>org.powermock</groupId> 49 <artifactId>powermock-api-mockito2</artifactId> 50 <version>${powermock.version}</version> 51 <scope>test</scope> 52 </dependency> 53 54 <dependency> 55 <groupId>org.powermock</groupId> 56 <artifactId>powermock-module-junit4-rule-agent</artifactId> 57 <version>${powermock.version}</version> 58 <scope>test</scope> 59 </dependency> 60 61 <dependency> 62 <groupId>org.mockito</groupId> 63 <artifactId>mockito-core</artifactId> 64 <version>3.12.4</version> <!--$NO-MVN-MAN-VER$--> 65 <scope>test</scope> 66 </dependency> 67</dependencies> 68 69<build> 70 <plugins> 71 <plugin> 72 <groupId>org.springframework.boot</groupId> 73 <artifactId>spring-boot-maven-plugin</artifactId> 74 <executions> 75 <execution> 76 <goals> 77 <goal>repackage</goal> 78 </goals> 79 </execution> 80 </executions> 81 </plugin> 82 83 <plugin> 84 <groupId>org.apache.maven.plugins</groupId> 85 <artifactId>maven-surefire-plugin</artifactId> 86 <version>3.0.0-M7</version> 87 <configuration> 88 <argLine>-Djdk.attach.allowAttachSelf=true</argLine> 89 </configuration> 90 </plugin> 91 </plugins> 92</build>
註:-Djdk.attach.allowAttachSelf=true 係用黎解決 JDK 8 之後既新版 JDKs 所出現既「Can not attach to current VM」問題。
參考資料:

4.2 寫 Java code

先建立一個典型既 Spring Boot web application。
寫一個 dummy component:
@Component public class MyComponent { }
之後我地可以寫 test code:
1@PrepareForTest({ StringUtils.class, RandomStringUtils.class }) 2@PowerMockIgnore({ "com.sun.org.apache.xerces.*", "javax.xml.*", "org.xml.*", "javax.management.*" }) 3@SpringBootTest 4@RunWith(SpringRunner.class) 5public class MockStaticSpringTest { 6 7 @Autowired 8 MyComponent myComponent; 9 10 @Rule 11 public PowerMockRule powerMockRule = new PowerMockRule(); 12 13 @Before 14 public void setUp() { 15 PowerMockito.spy(StringUtils.class); 16 PowerMockito.mockStatic(RandomStringUtils.class); 17 } 18 19 // Spring Boot test,可以測試 Spring context 能唔能夠成功 load 到 20 @Test 21 public void contextLoads() { 22 assertNotNull(myComponent); 23 } 24 25 @Test 26 public void test_mockStatic_StringUtils() { 27 assertTrue(StringUtils.isBlank(" ")); 28 PowerMockito.when(StringUtils.isBlank(any())).thenReturn(false); 29 assertFalse(StringUtils.isBlank(" ")); 30 } 31 32 @Test 33 public void test_mockStatic_RandomStringUtils() { 34 assertNull(RandomStringUtils.randomAlphabetic(10)); 35 PowerMockito.when(RandomStringUtils.randomAlphabetic(anyInt())).thenReturn("Hello World!"); 36 assertEquals("Hello World!", RandomStringUtils.randomAlphabetic(10)); 37 } 38}
註:
  • 我地用既係 SpringRunner 而唔係 PowerMockRunner
    • 正因為咁,所以我地要加 @Rule public PowerMockRule powerMockRule = new PowerMockRule();
      • 呢個 property 一定要係 public
      • 呢個 property 要先 initialize,例如 new PowerMockRule()
  • @PowerMockIgnore 有可能需要用到。
  • 我地要 mock static 既 class 係 Apache Commons Lang3 既 StringUtils 以及 RandomStringUtils
  • PowerMock 使用上其實同 Mockito 係非常相似。
    • PowerMockito.mockStatic(class) 默認會令 mock object 既所有 methods 都冇任何 implementation,即係如果有 return type,佢就會返回 null 或者 false 之類既默認 value,除非我地用 when-then 既寫法賦予被測試既 method 一啲新既 behavior。
    • PowerMockito.spy(class) 係當我地需要 mock object 默認用返本身既 implementation,除非我地用 when-then 既寫法賦予被測試既 method 一啲新既 behavior。