In this tutorial, I will guide you to mock static methods in Unit Test using PowerMock!
If you do not know about mock in the Unit Test, I can say it like this: Mock is a solution that helps us to create a mock object so that we can specify the behavior of an object in Unit Test. For example, you have an object that connects to the SFTP server but in the Unit Test you cannot set up a real SFTP server, so you cannot test the connection function of this object to the SFTP server. In this case, you can create a mock object that simulates the behavior of the connection object to the SFTP server and specifies that when the other object calls to the method making the connection to SFTP of this object, it will return a value.
Why do we have to use PowerMock to mock static methods? Simply because there is only PowerMock support for us to do this.
OK, now let’s go to the main topic of this tutorial!
I will create a Maven project as an example for you to understand. My project is as follows:
We will now add the necessary dependencies of JUnit and PowerMock to our project. Open the pom.xml file and add the following dependencies:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<dependency> <groupId>org.powermock</groupId> <artifactId>powermock-api-mockito</artifactId> <version>1.6.5</version> <scope>test</scope> </dependency> <dependency> <groupId>org.powermock</groupId> <artifactId>powermock-module-junit4</artifactId> <version>1.6.5</version> <scope>test</scope> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> |
And the class containing the static method that we need to mock, will have something like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
package com.huongdanjava.mockstatic; import java.io.BufferedReader; import java.io.InputStreamReader; public class SSHCommandLineHelper { /** * Execute command: "<strong>ssh <i>server</i> test -e <i>remoteFilePath</i> && echo 1 || echo 0</strong>" to check whether * a file is existing or not in remote SSH server. * <p /> * The pre-condition is: we can use SSH to login into other server without username and password. * * @param server * SSH server. * @param remoteFilePath * Path of remote file on SSH server. * @return True if executing success otherwise will false. */ public boolean checkFileExistingWithoutUsernamePassword(String server, String remoteFilePath) { StringBuilder sb = new StringBuilder(); sb.append("ssh "); sb.append(server); sb.append(" test -e "); sb.append(remoteFilePath); sb.append(" && echo 1 || echo 0"); return executeCommandOnRemote(sb.toString()); } /** * Execute the command on remote SSH server. * * @param command * The command. * @return True if executing success otherwise will false. */ private boolean executeCommandOnRemote(String command) { StringBuffer output = new StringBuffer(); Process p; try { p = Runtime.getRuntime().exec(command); p.waitFor(); BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream())); String line = ""; while ((line = reader.readLine()) != null) { output.append(line + "\n"); } } catch (Exception e) { e.printStackTrace(); } return "1".equals(output.toString().trim()); } } |
The purpose of this class is to use Java to execute a command line that checks the existence of a file on another machine using SSH without having to use a user and password to log in (to run a program using this class, we have to set the login to another machine without user and password).
As you can see, in this class, I used the Runtime object with the getRuntime() static method to execute a command line in Java. In Unit Test, how can we simulate another machine to test the checkFileExistingWithoutUsernamePassword() static method in the SSHCommandLineHelper class? Our solution is to use mock only.
First, create a SSHCommandLineHelperTest class in the test directory with the package as com.huongdanjava.mockstatic as follows:
In this class, first declare annotation @PrepareForTest and @RunWith first as follows:
1 2 3 4 5 6 7 8 9 10 |
package com.huongdanjava.mockstatic; import org.junit.runner.RunWith; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; @RunWith(PowerMockRunner.class) @PrepareForTest({SSHCommandLineHelper.class}) public class SSHCommandLineHelperTest { } |
In the @Before section of the Unit Test, we will declare using PowerMock to mock the static method in the Runtime class as follows:
1 2 3 4 |
@Before public void init() { PowerMockito.mockStatic(Runtime.class); } |
Now, we will write a test case for when we run the program to check if the file exists on another SSH machine, the checkFileExistingWithoutUsernamePassword() static method returns the value TRUE!
The contents of the testCheckFileExistingSuccessWithoutUsernamePassword() method are as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
@Test public void testCheckFileExistingSuccessWithoutUsernamePassword() throws IOException { // Declare mock object for Runtime object. Runtime mockedRuntime = PowerMockito.mock(Runtime.class); PowerMockito.when(Runtime.getRuntime()).thenReturn(mockedRuntime); // Declare mock object for Process object Process mockedProcess = PowerMockito.mock(Process.class); // Because this is a success case, then the Process object will return "1" when executing command line InputStream is = new ByteArrayInputStream("1".getBytes()); PowerMockito.when(mockedProcess.getInputStream()).thenReturn(is); PowerMockito.when(mockedRuntime.exec(anyString())).thenReturn(mockedProcess); // Declare SSHCommandLineHelper object SSHCommandLineHelper helper = new SSHCommandLineHelper(); // Assert when calling method will return TRUE Assert.assertTrue(helper.checkFileExistingWithoutUsernamePassword("abc", "abc")); } |
Result:
In case we test for non-existent files, just modify a little as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
@Test public void testCheckFileExistingSuccessWithoutUsernamePassword() throws IOException { // Declare mock object for Runtime object. Runtime mockedRuntime = PowerMockito.mock(Runtime.class); PowerMockito.when(Runtime.getRuntime()).thenReturn(mockedRuntime); // Declare mock object for Process object Process mockedProcess = PowerMockito.mock(Process.class); // Because this isn't a success case, then the Process object will return "0" when executing command line InputStream is = new ByteArrayInputStream("0".getBytes()); PowerMockito.when(mockedProcess.getInputStream()).thenReturn(is); PowerMockito.when(mockedRuntime.exec(anyString())).thenReturn(mockedProcess); // Declare SSHCommandLineHelper object SSHCommandLineHelper helper = new SSHCommandLineHelper(); //Assert when calling method will return FALSE Assert.assertFalse(helper.checkFileExistingWithoutUsernamePassword("abc", "abc")); } |
Result:
The code for the SSHCommandLineHelperTest class is as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
package com.huongdanjava.mockstatic; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.powermock.api.mockito.PowerMockito; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import static org.mockito.Matchers.anyString; @RunWith(PowerMockRunner.class) @PrepareForTest({SSHCommandLineHelper.class}) public class SSHCommandLineHelperTest { @Before public void init() { PowerMockito.mockStatic(Runtime.class); } @Test public void testCheckFileExistingSuccessWithoutUsernamePassword() throws IOException { Runtime mockedRuntime = PowerMockito.mock(Runtime.class); PowerMockito.when(Runtime.getRuntime()).thenReturn(mockedRuntime); Process mockedProcess = PowerMockito.mock(Process.class); InputStream is = new ByteArrayInputStream("1".getBytes()); PowerMockito.when(mockedProcess.getInputStream()).thenReturn(is); PowerMockito.when(mockedRuntime.exec(anyString())).thenReturn(mockedProcess); SSHCommandLineHelper helper = new SSHCommandLineHelper(); Assert.assertTrue(helper.checkFileExistingWithoutUsernamePassword("abc", "abc")); } @Test public void testCheckFileNotExistingWithoutUsernamePassword() throws IOException { Runtime mockedRuntime = PowerMockito.mock(Runtime.class); PowerMockito.when(Runtime.getRuntime()).thenReturn(mockedRuntime); Process mockedProcess = PowerMockito.mock(Process.class); InputStream is = new ByteArrayInputStream("0".getBytes()); PowerMockito.when(mockedProcess.getInputStream()).thenReturn(is); PowerMockito.when(mockedRuntime.exec(anyString())).thenReturn(mockedProcess); SSHCommandLineHelper helper = new SSHCommandLineHelper(); Assert.assertFalse(helper.checkFileExistingWithoutUsernamePassword("abc", "abc")); } } |