Use PowerMock to write Java UT.

Pom files introduce dependencies

<! -- PowerMock JUnit4.4+ Module --> <dependency> <groupId>org. powerMock </groupId> <artifactId>powermock-module-junit4</artifactId> <version>2.0. 0</version> <scope>test</scope> </dependency> <! --> <dependency> <groupId>org. PowerMock </groupId> The < artifactId > powermock - API - mockito2 < / artifactId > < version >2.0. 0</version> <scope>test</scope> </dependency> <dependency> <groupId>junit</groupId> <artifactId> <version>4.11</version> <scope>test</scope> </dependency>Copy the code

Relevant notes

// Tell JUnit to test using PowerMockRunner
@RunWith(PowerMockRunner.class) 

// All classes that need to be tested are listed here. This applies to classes that simulate final classes or classes with final, private, static, or native methods
@PrepareForTest({RandomUtil.class}) 

// Ignore the classes in the package (do not load the specified package); Used to resolve a ClassLoader error after powerMock is used
@PowerMockIgnore("javax.management.*") 

// Create an instance that calls the methods of real code
@InjectMocks

// A Mock instance is created with all properties and methods null (0 or NULL).
@Mock
Copy the code

The mock return value

// Mock expected value
1. PowerMockito.doReturn(expected).when(mockList).get(index);
2. PowerMockito.when(mockList.get(index)).thenReturn(expected);

// The mock exception returns
1. PowerMockito.doThrow(new IndexOutOfBoundsException()).when(mockList).get(index);
2. PowerMockito.when(mockList.get(index)).thenThrow(new IndexOutOfBoundsException());

// No return value
PowerMockito.doNothing().when(mockList).clear();

// Note: when().thenreturn () mode executes the original method, while doReturn().when() mode does not.

Copy the code

Check back

Mockito.verify(mockList).clear(); Mockito.verify(mockList, mockito.times (1)).clear(); // Validate the number of calls to the methodCopy the code

The mock parameters

AnyInt (), mockito.anystring, mockito.any (Class clazz), etc.

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

The instance

Mock for different classes or methods.

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

}

-----MockServiceImpl.class
@Service
public class MockServiceImpl {@Autowired
  privateMockMapper mockMapper;public int count(MockModel model) {returnMockMapper. 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) {
        returnrandom.nextInt(bound); }}Copy the code

Mock normal methods

@RunWith(PowerMockRunner.class) 
@PrepareForTest({MockUtil.class}) 
@PowerMockIgnore("javax.management.*")
public class MockExample {
    // Inject a sample of the @mock annotation
    @InjectMocks
    private MockServiceImpl mockService;
    @Mock
    private MockMapper mockMapper;
    
    /** * mock ordinary methods */
    @Test
    public void testSelectAppAdvertisementList(a) {
        MockModel model = new MockModel();
        PowerMockito.when(mockMapper.count(model)).thenReturn(2);
        Assert.assertEquals(2, mockService.count(model)); }}Copy the code

Mock static methods

  1. Statement:
PowerMockito.mockStatic(Class clazz);
PrepareForTest({Class clazz});
Copy the code
  1. use
@RunWith(PowerMockRunner.class) 
@PrepareForTest({MockUtil.class}) 
@PowerMockIgnore("javax.management.*")
public class MockStaticExample {@Test 
  public void testStaticMethod(a) {PowerMockito. MockStatic (MockUtil. Class); PowerMockito.when(MockUtil.nextInt(10)).thenReturn(7); Assert.assertEquals(7, MockUtil.nextInt(10)); }}Copy the code

A constructor within a Mock method

  1. The statement
  • Pass the specified parameters to construct
PowerMockito.whenNew(*.class).withArguments(argument1, ...) .thenReturn(file)Copy the code
  • Construct regardless of parameters
PowerMockito.whenNew(*.class).withAnyArguments().thenReturn(file)
Copy the code
  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(a) 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("Return value false", FileUtils.isFile(fileName)); }}Copy the code

The mock class’s partial method spy

If we want to mock only part of an object and want the other methods to be the same, we can use the PowerMockito.spy method instead of the powerMockito.mock method. Thus, the method set by the WHEN statement calls the mock method; Methods that are not set by the WHEN statement call the original method.

  1. Statement:
PowerMockito.spy(Class clazz); / / class
T PowerMockito.spy(T object); / / spy object
Copy the code
  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(a) {
        String string = null;
        boolean expected = true; PowerMockito.spy(StringUtils.class); PowerMockito.when(StringUtils.isEmpty(string)).thenReturn(! expected);boolean actual = StringUtils.isNotEmpty(string);
        Assert.assertEquals("Return values are not equal", expected, actual); }}Copy the code

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(a) {
        Long userId = 1L;
        boolean expected = false;
        UserService userService = PowerMockito.spy(newUserService()); PowerMockito.when(userService.isSuperUser(userId)).thenReturn(! expected);boolean actual = userService.isNotSuperUser(userId);
        Assert.assertEquals("Return values are not equal", expected, actual); }}Copy the code

The mock system class

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

public class SystemClassUser {

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

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

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

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

		assertEquals("something".newSystemClassUser().performEncode()); verifyAll(); }}Copy the code

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(a) {
        PowerMockito.mockStatic(Runtime.class);

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

        // do the rest of your test}}Copy the code

Mock class private methods, properties

  1. Statement:
  • Mock private properties
// The first way; Native JUnit is used for unit testing
ReflectionTestUtils.setField(obj, fieldName, value);
// The second way; Whitebox. SetInternalState powermock
Whitebox.setInternalState(obj, fieldName, value);
Copy the code
  • Mock private methods
1. PowerMockito.stub(PowerMockito.method(UserService.class, "isSuperUser", Long.class)).toReturn(! expected);2. PowerMockito.when(userService, "isSuperUser", userId).thenReturn(! expected);Copy the code
  1. use
@Service
public class UserService {

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

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

}

-----UT
public class UserServiceTest {

    @Autowired
    private UserService userService;

    // Mock private attributes
    @Test
    public void testGetUserLimit(a) {
        Long expected = 1000L;
        ReflectionTestUtils.setField(userService, "userLimit", expected);
        // or the following kind
        // Whitebox.setInternalState(userService, "userLimit", expected);
        Long actual = userService.getUserLimit();
        Assert.assertEquals("Return values are not equal", expected, actual);
    }
    // Mock private methods
    @Test
    public void testIsNotSuperUser(a) 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("Return values are not equal", expected, actual); }}Copy the code

Refer to the link

Github.com/powermock/p…