Search code examples
junitmockitojunit4powermockito

Unable to Mock functions inside static method Powermock


I am writing unit test for the below code using junit and mockito

 public class Abc implements Runnable
    {
        private static ServerSocket server;  
        private static int port;      
        public Abc(int cPort)
        {
            port = cPort;
        }

        public void run()
        {
            init();
        }

        public static void init()
        {
            try {
                server = new ServerSocket(port);
                ...something...
                client.close();
                } 
            }
            catch(IOException e)
            {   
                System.out.println("Exception inside init()...");
                e.printStackTrace();
            }
        }
    };

Unit test I have written

@RunWith(PowerMockRunner.class)
@PrepareForTest({ServerSocket.class})
public class abcTest {

    @Mock (name = "server") //same name as private var.
    ServerSocket mockServer;        
    @InjectMocks
    Abc abc;

    @Test
    public void testInit() throws Exception {
        int port = 1880;
        Socket mockClient = Mockito.mock(Socket.class);  
        PowerMockito.whenNew(ServerSocket.class).
                withArguments(anyInt()).thenReturn(mockServer);         
        abc = new Abc(port);
        Abc.init();         
        PowerMockito.verifyNew(ServerSocket.class).withArguments(port);
    }
};

But the call always go to original function definition. I am using junit 4.11 with mockito 2.28.2 and powermockito 2.0.2. I'm using java after a long time. Now its feel like kind of new. Please correct me if anything wrong in the code also.


Solution

  • You will need to change your PrepareForTest annotation to @PrepareForTest({Abc.class}).

    From the PowerMockito docu:

    This annotation tells PowerMock to prepare certain classes for testing. Classes needed to be defined using this annotation are typically those that needs to be byte-code manipulated

    In this case that refers to the class which creates the new instance of ServerSocket.
    ServerSocket itself is a non-final public class that does not require special handling from PowerMockito (instead Mockito can deal with this class on its own).


    You could also change your test to do the following:

    @Test
    public void testInit() throws Exception {
        int port = 1880;
    
        ServerSocket mockServer = Mockito.mock(ServerSocket.class);
    
        PowerMockito.whenNew(ServerSocket.class)
                    .withArguments(Mockito.anyInt()).thenReturn(mockServer);
    
        Abc.port = port;
        Abc.init();     
    
        PowerMockito.verifyNew(ServerSocket.class).withArguments(port);
    }
    

    • (This first point is unrelated to whether the test fails or succeeds)
      I do not know why you mix object's and static method behaviour together, but I think you should change that.

      In the test instead of creatic an ABC object, just could just set the static port variable directly.
      Or alternatively change the whole ABC class into an object.

    • @InjectMocks failed for me as there is no default constructor
      (Actually I got an error message in the console when trying to execute your code)

    • Additonaly you create a new instance of ABC in your test, which would have overwritten the things done by the annotations. Also as server is created during the init call, there is no need to inject a mock for it.

    • powermockito 2.0.2 actually depends on junit 4.12, so I am not sure what effects downgrading to an older version might have.

    • Socket mockClient seemed somewhat unrelated to the code your posted, so I removed it from my example in the answer, however as you use a client (I assume that is your Socket) in your code your probably need to do some mocking for that as well and provide the mock to the method accordingly.