JAVA JUnit Test

Use powermock to write java UT.

pom file introduces related dependencies

<!-- PowerMock JUnit 4.4+ Module -->
<dependency>
  <groupId>org.powermock</groupId>
  <artifactId>powermock-module-junit4</artifactId>
  <version>2.0.0</version>
  <scope>test</scope>
</dependency>
<!-- PowerMock Mockito2 API -->
<dependency>
  <groupId>org.powermock</groupId>
  <artifactId>powermock-api-mockito2</artifactId>
  <version>2.0.0</version>
  <scope>test</scope>
</dependency>
<dependency>
  <groupId>junit</groupId>
  <artifactId>junit</artifactId>
  <version>4.11</version>
  <scope>test</scope>
</dependency>
复制代码

Related explanations

// 告诉JUnit使用PowerMockRunner进行测试
@RunWith(PowerMockRunner.class) 

// 所有需要测试的类列在此处,适用于模拟final类或有final, private, static, native方法的类
@PrepareForTest({RandomUtil.class}) 

//忽略的程序包中的类(不加载指定包); 常用于解决使用powermock后,提示classloader错误
@PowerMockIgnore("javax.management.*") 

// 创建一个实例,这个实例可以调用真实代码的方法
@InjectMocks

// 创建了一个全部Mock的实例,所有属性和方法全被置空(0或者null)。
@Mock
复制代码

mock return value

// mock期望值
1. PowerMockito.doReturn(expected).when(mockList).get(index);
2. PowerMockito.when(mockList.get(index)).thenReturn(expected);

// mock异常返回
1. PowerMockito.doThrow(new IndexOutOfBoundsException()).when(mockList).get(index);
2. PowerMockito.when(mockList.get(index)).thenThrow(new IndexOutOfBoundsException());

// 无返回值
PowerMockito.doNothing().when(mockList).clear();

//注意:when().thenReturn()模式会执行原方法,而doReturn().when()模式不会执行原方法。

复制代码

check return

Mockito.verify(mockList).clear(); //验证是否方法被调用

Mockito.verify(mockList, Mockito.times(1)).clear(); //验证方法的调用次数

复制代码

mock parameter

Mockito provides Mockito.anyInt(), Mockito.anyString, Mockito.any(Class clazz), etc. to represent arbitrary values.

When we use parameter matchers, all parameters should use matchers. If you want to specify a specific value for a parameter, you need to use the Mockito.eq() method.

Example

For different classes or methods of mocking.

------MockMapper.class
public interface MockMapper {
  public int count(MockModel model);

}

-----MockServiceImpl.class
@Service
public class MockServiceImpl {
  @Autowired
  private MockMapper mockMapper;

  public int count(MockModel model) {
    return mockMapper.count(model);
  }
    
    public boolean makeFile(String path) {
       File file = new File(path);
       return file.exists();
    }
}

------MockUtil.class
public class MockUtil {
    private static final Random random = new Random();
    
    public static int nextInt(int bound) {
        return random.nextInt(bound);
    }
}

复制代码

mock normal method

@RunWith(PowerMockRunner.class) 
@PrepareForTest({MockUtil.class}) 
@PowerMockIgnore("javax.management.*")
public class MockExample {
    // 将@Mock注解的示例注入进来
    @InjectMocks
    private MockServiceImpl mockService;
    @Mock
    private MockMapper mockMapper;
    
    /**
     * mock普通方法
     */
    @Test
    public void testSelectAppAdvertisementList() {
        MockModel model = new MockModel();
        PowerMockito.when(mockMapper.count(model)).thenReturn(2);
        Assert.assertEquals(2, mockService.count(model));
    }
}
复制代码

Mock static method

  1. statement:
PowerMockito.mockStatic(Class clazz);
PrepareForTest({Class clazz});
复制代码
  1. use
@RunWith(PowerMockRunner.class) 
@PrepareForTest({MockUtil.class}) 
@PowerMockIgnore("javax.management.*")
public class MockStaticExample {
  @Test 
  public void testStaticMethod() { 
    PowerMockito.mockStatic(MockUtil.class); 
    PowerMockito.when(MockUtil.nextInt(10)).thenReturn(7); 
    Assert.assertEquals(7, MockUtil.nextInt(10)); 
  }
}
复制代码

Constructor inside Mock method

  1. statement
  • Construct by passing specified parameters
PowerMockito.whenNew(*.class).withArguments(argument1, ...).thenReturn(file)
复制代码
  • Construct regardless of parameters
PowerMockito.whenNew(*.class).withAnyArguments().thenReturn(file)
复制代码
  1. use
public final class FileUtils {

    public static boolean isFile(String fileName) {
        return new File(fileName).isFile();
    }

}

----UT
@RunWith(PowerMockRunner.class)

@PrepareForTest({FileUtils.class})
public class MockStructureExample {
    @Test
    public void testIsFile() throws Exception {
        String fileName = "test.txt";
        File file = PowerMockito.mock(File.class);
        PowerMockito.whenNew(File.class).withArguments(fileName).thenReturn(file);
        PowerMockito.when(file.isFile()).thenReturn(true);
        Assert.assertTrue("返回值为假", FileUtils.isFile(fileName));
    }
}
复制代码

Some methods of mock class spy

If an object, we only want to mock some of its methods, and want other methods to be the same as the original, you can use the PowerMockito.spy method instead of the PowerMockito.mock method. Therefore, the method set by the when statement calls the simulated method; and the method that is not set by the when statement calls the original method.

  1. statement:
PowerMockito.spy(Class clazz); // 类
T PowerMockito.spy(T object); //spy对象
复制代码
  1. use

Example 1

public class StringUtils {

    public static boolean isNotEmpty(final CharSequence cs) {
        return !isEmpty(cs);
    }
    
    public static boolean isEmpty(final CharSequence cs) {
        return cs == null || cs.length() == 0;
    }
}

----UT
@RunWith(PowerMockRunner.class)
@PrepareForTest({ StringUtils.class })
public class StringUtilsTest {

    @Test
    public void testIsNotEmpty() {
        String string = null;
        boolean expected = true;
        PowerMockito.spy(StringUtils.class);
        PowerMockito.when(StringUtils.isEmpty(string)).thenReturn(!expected);
        boolean actual = StringUtils.isNotEmpty(string);
        Assert.assertEquals("返回值不相等", expected, actual);
    }

}
复制代码

Example 2 spy object

public class UserService {

    private Long superUserId;

    public boolean isNotSuperUser(Long userId) {
        return !isSuperUser(userId);
    }

    public boolean isSuperUser(Long userId) {
        return Objects.equals(userId, superUserId);
    }
}

---- UT
@RunWith(PowerMockRunner.class)
public class UserServiceTest {

    @Test
    public void testIsNotSuperUser() {
        Long userId = 1L;
        boolean expected = false;
        UserService userService = PowerMockito.spy(new UserService());
        PowerMockito.when(userService.isSuperUser(userId)).thenReturn(!expected);
        boolean actual = userService.isNotSuperUser(userId);
        Assert.assertEquals("返回值不相等", expected, actual);
    }

}
复制代码

mock system class

Note: Since the URLEncoder class is a system class, we should prepare SystemClassUser for testing as this is the class URLEncoder that calls the encode method. Example 1

public class SystemClassUser {

	public String performEncode() throws UnsupportedEncodingException {
		return URLEncoder.encode("string", "enc");
	}
}

---UT
@RunWith(PowerMockRunner.class)
@PrepareForTest( { SystemClassUser.class })
public class SystemClassUserTest {

	@Test
	public void assertThatMockingOfNonFinalSystemClassesWorks() throws Exception {
		mockStatic(URLEncoder.class);

		expect(URLEncoder.encode("string", "enc")).andReturn("something");
		replayAll();

		assertEquals("something", new SystemClassUser().performEncode());

		verifyAll();
	}
}
复制代码

Example 2

public class AppShell {
  public Process exec(String command) {
    return Runtime.getRuntime().exec(command);
  }
}

----UT
@RunWith(PowerMockRunner.class)
@PrepareForTest(AppShell.class)
public class AppShellTest {

    @Mock private Runtime mockRuntime;

    @Test
    public void test() {
        PowerMockito.mockStatic(Runtime.class);

        when(Runtime.getRuntime()).thenReturn(mockRuntime);
        when(mockRuntime.exec()).thenReturn("whatever you want");

        // do the rest of your test
    }
}
复制代码

Private methods and properties of mock classes

  1. statement:
  • mock private property
// 第一种方式; 原生JUnit进行单元测试时使用
ReflectionTestUtils.setField(obj, fieldName, value);
// 第二种方式;Whitebox.setInternalState powermock时使用
Whitebox.setInternalState(obj, fieldName, value);
复制代码
  • mock private method
1. PowerMockito.stub(PowerMockito.method(UserService.class, "isSuperUser", Long.class)).toReturn(!expected);
2. PowerMockito.when(userService, "isSuperUser", userId).thenReturn(!expected);
复制代码
  1. use
@Service
public class UserService {

    @Value("${system.userLimit}")
    private Long userLimit;

    public Long getUserLimit() {
        return userLimit;
    }
    
    private boolean isSuperUser(Long userId) {
        return Objects.equals(userId, superUserId);
    }

}

-----UT
public class UserServiceTest {

    @Autowired
    private UserService userService;

    // mock 私有属性
    @Test
    public void testGetUserLimit() {
        Long expected = 1000L;
        ReflectionTestUtils.setField(userService, "userLimit", expected);
        // or 下面这一种
        // Whitebox.setInternalState(userService, "userLimit", expected);
        Long actual = userService.getUserLimit();
        Assert.assertEquals("返回值不相等", expected, actual);
    }
    // mock 私有方法
    @Test
    public void testIsNotSuperUser() throws Exception {
        Long userId = 1L;
        boolean expected = false;
        UserService userService = PowerMockito.spy(new UserService());
        PowerMockito.when(userService, "isSuperUser", userId).thenReturn(!expected);
        PowerMockito.stub(PowerMockito.method(UserService.class, "isSuperUser", Long.class)).toReturn(!expected);
        boolean actual = userService.isNotSuperUser(userId);
        Assert.assertEquals("返回值不相等", expected, actual);
    }

}
复制代码

Reference link

github.com/powermock/p…

Guess you like

Origin juejin.im/post/6950490313123168292