Mocking InetAddress - how to mock getting a new local address?

5,800 views
Skip to first unread message

Martin

unread,
Nov 4, 2010, 5:57:16 PM11/4/10
to PowerMock
Hi,

I have a class wrapping InetAddress and I'd like to do a staticMock on
InetAddress with TestNG and EasyMock, without success.

The error is an EasyMock error, that I beleive tells me it's not
finding the mock:
FAILED: testGetLocalHostAddress_Exception
java.lang.IllegalArgumentException: Not a mock: java.lang.Class
at
org.easymock.internal.ClassExtensionHelper.getControl(ClassExtensionHelper.java:
62)
at org.easymock.EasyMock.getControl(EasyMock.java:2068)
at org.easymock.EasyMock.reset(EasyMock.java:1983)
at
com.wellsfargo.sims.common.util.InetAddressTest.testGetLocalHostAddress_Exception(InetAddressTest.java:
3 0)


The class is:


import java.net.InetAddress;
import java.net.UnknownHostException;
import org.easymock.EasyMock;
import org.powermock.api.easymock.PowerMock;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.testng.annotations.Test;

@PrepareForTest(InetAddress.class)
public class InetAddressTest {

@Test()
public void testGetLocalHostAddress_Exception() throws
UnknownHostException
{
PowerMock.mockStatic(InetAddress.class); // Should setup a
static mock in EasyMock
EasyMock.reset(InetAddress.class); // Failure --
EasyMock fails to find the static mock
EasyMock.expect(InetAddress.getLocalHost()).andThrow(
new UnknownHostException());
EasyMock.replay(InetAddress.class);

try {
InetAddress.getLocalHost();
fail("Expected exception");
}
catch (Exception e) {
// NOP
}
} // public void testGetLocalHostAddress_Exception()
}


This is on PM 1.4.6, EM 3.

TIA

Martin

Johan Haleby

unread,
Nov 5, 2010, 3:20:23 AM11/5/10
to powe...@googlegroups.com
Hi, 

What happens if you remove reset?

/Johan


--
You received this message because you are subscribed to the Google Groups "PowerMock" group.
To post to this group, send email to powe...@googlegroups.com.
To unsubscribe from this group, send email to powermock+...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/powermock?hl=en.


Martin B

unread,
Nov 5, 2010, 3:53:51 PM11/5/10
to powe...@googlegroups.com
The reset makes no difference. It's implicit that there's one after creating the mock, but it doesn't hurt to expound the point, especially when your trying to make something work!

Same error: EasyMock is not finding the mock, so, I assume, there's a breakdown between the PowerMock.mockStatic and EasyMock when EasyMock goes looking for the subject of the expects..

Offering this up to someone who has more experience in this part of the code.

Thanks in advance,

Martin

Johan Haleby

unread,
Nov 5, 2010, 4:41:32 PM11/5/10
to powe...@googlegroups.com
Alright the problem is probably due to InetAddress being a system class. As mentioned in the FAQ you need to deal with system classes specially because it's impossible for PowerMock to change their byte-code. Have a look at the last method in this test to see an example. It's written in JUnit but it should work the same way with TestNG.

/Johan

Martin B

unread,
Nov 15, 2010, 6:13:32 PM11/15/10
to powe...@googlegroups.com
Hi Johan,

I did some testing with TestNG 5.14.2, EasyMock 3 and PowerMock 1.4.6 around this. I addressed the point you raised below by delegating the system call into a method in the class under test. I then partially mocked the class under test, specifying only the method that performing the system call.

The outcome was the same as before:
     no last call on a mock available


The class under test, the test and stack trace are below. It looks like an issue with PM expectsPrivate intercepting the expects call to EasyMock...

I would appreciate any help!

TIA 

Martin

---------

The class under test:

import java.net.InetAddress;
import java.net.UnknownHostException;

public class IAX {

    private static InetAddress IA;


    public InetAddress getIA() {
        if (IA == null) {
            IA = getLocalHost();
        }

        return IA;
    }


    //    public static InetAddress getSIA() {
    //        return getLocalHost();
    //    }

    private final InetAddress getLocalHost() {
        try {
            return InetAddress.getLocalHost();
        }
        catch (final UnknownHostException e) {
            return null;
        }
    }
}

---------
The test

import static org.testng.Assert.assertNotNull;

import java.net.InetAddress;
import java.net.UnknownHostException;

import org.powermock.api.easymock.PowerMock;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;


@PrepareForTest(IAX.class)
public class IAXTest {

    InetAddress addr;
    IAX classUnderTest;


    @BeforeClass
    public void setUp() throws UnknownHostException {
        addr = InetAddress.getLocalHost();
        classUnderTest = PowerMock.createPartialMock(IAX.class, "getLocalHost");
    }


    /**
     * Test method for {@link IAX#getIA()}.
     *
     * @throws Exception
     */
    @Test()
    public void testGetIA() throws Exception {
        PowerMock.reset(classUnderTest);
        /*
        PowerMock.expectPrivate(classUnderTest, "getLocalHost").andThrow(
                new UnknownHostException());
        */
        PowerMock.expectPrivate(classUnderTest, "getLocalHost").andReturn(addr);
        PowerMock.replay(classUnderTest);
        assertNotNull(classUnderTest.getIA());
    }


    /**
     * Test method for {@link IAX#getSIA()}.
     *
     * @throws Exception
     */
    //@Test()
    public void testGetSIA() throws Exception {
        PowerMock.reset(classUnderTest);
        /*
        PowerMock.expectPrivate(classUnderTest, "getLocalHost").andThrow(
                new UnknownHostException());
        */
        PowerMock.expectPrivate(classUnderTest, "getLocalHost").andReturn(
                InetAddress.getLocalHost());
        PowerMock.replay(classUnderTest);

        assertNotNull(IA.getSIA());
    }

}




--------
The stack trace

FAILED: testGetIA
java.lang.IllegalStateException: no last call on a mock available
    at org.easymock.EasyMock.getControlForLastCall(EasyMock.java:521)
    at org.easymock.EasyMock.expectLastCall(EasyMock.java:512)
    at org.powermock.api.easymock.PowerMock.doExpectPrivate(PowerMock.java:2247)
    at org.powermock.api.easymock.PowerMock.expectPrivate(PowerMock.java:1409)
    at org.powermock.api.easymock.PowerMock.expectPrivate(PowerMock.java:1420)
    at org.powermock.api.easymock.PowerMock.expectPrivate(PowerMock.java:1366)
    at IAXTest.testGetIA(IAXTest.java:42)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:74)
    at org.testng.internal.Invoker.invokeMethod(Invoker.java:675)
    at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:848)
    at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:1170)
    at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:125)
    at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:109)
    at org.testng.TestRunner.runWorkers(TestRunner.java:1119)
    at org.testng.TestRunner.privateRun(TestRunner.java:744)
    at org.testng.TestRunner.run(TestRunner.java:600)
    at org.testng.SuiteRunner.runTest(SuiteRunner.java:315)
    at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:310)
    at org.testng.SuiteRunner.privateRun(SuiteRunner.java:272)
    at org.testng.SuiteRunner.run(SuiteRunner.java:221)
    at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)
    at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:86)
    at org.testng.TestNG.runSuitesSequentially(TestNG.java:945)
    at org.testng.TestNG.runSuitesLocally(TestNG.java:884)
    at org.testng.TestNG.run(TestNG.java:818)
    at org.testng.remote.RemoteTestNG.run(RemoteTestNG.java:96)
    at org.testng.remote.RemoteTestNG.main(RemoteTestNG.java:179)

Johan Haleby

unread,
Nov 16, 2010, 5:29:54 AM11/16/10
to powe...@googlegroups.com
Hi,

Try extending your test from PowerMockTestCase. You shouldn't need to though, I think it may be a bug.

/Johan

Johan Haleby

unread,
Nov 16, 2010, 4:12:10 PM11/16/10
to powe...@googlegroups.com
After a bit of investigation I don't think it's a bug in PowerMock. It seems to me like Intellij ignores the use of the PowerMockObjectFactory when specified in the TestNG suite xml file. But if just a single class in the xml uses the PowerMockObjectFactory in any way (e.g. by extending from PowerMockTestCase) it seems to run just fine. I don't see any issues when running the test suite from Maven. Perhaps you're experiencing a similar issue? Your example worked fine at my place when I executed it in a suite where the PowerMockObjectFactory was loaded correctly. It failed with the same exception that you experienced when the PowerMockObjectFactory wasn't used. So if you're not using Maven you may be better off extending from PowerMockTestCase or using the PowerMockObjectFactory programmatically as stated in the documentation.

/Johan

Martin B

unread,
Nov 17, 2010, 4:44:51 PM11/17/10
to powe...@googlegroups.com, jc.de...@gmail.com
CC'ing JC as you might be interested...

I pared down the test creating static and object versions of the scenario, created a second version extending PowerMockTestCase and created the Maven deployment package. The PowerMockTestCase version fails in Maven and in Eclipse Helios, 4 tests for 4. The plain version fails 4 for 4 in Eclipse, but strangely, one of the tests succeeds in Maven using mvn test. All test that expect a exception to be thrown fail.

From what I'm seeing, the behavior is at best inconsistent, and extending  PowerMockTestCase is moving in a direction I was hoping to avoid. I really like the annotation based approach of PowerMock... plus the promise of that power over plain EasyMock/Mockito!

Personnally I view this as a bug and I am going to open a ticket.

The Maven project is attached for your reference.

Thanks so much for your help Johan!

Martin
PowerMockTest.zip

Johan Haleby

unread,
Nov 18, 2010, 3:59:06 AM11/18/10
to powe...@googlegroups.com
Hi, 

I think you may be a bit confused with how PowerMock and EasyMock works in some cases. First off all 

  @Test
    public void testGetIAException() throws Exception {
        expectPrivate(classUnderTest, "getLocalHost").andThrow(uhe);
        replay(classUnderTest);
        assertNotNull(classUnderTest.getIA());
    }

will never work because just as the error message implies (java.lang.IllegalArgumentException: last method called on mock cannot throw java.net.UnknownHostException) it's not possible for the getLocalHost to throw the java.net.UnknownHostException because your getLocalHost method doesn't declare it! In order for that expectation to work you need to add the throws declaration. But even if you do that the test will not pass because it asserts the result to be  not null, but the test will (when fixed) throw an UnknownHostException. 

You're also not mocking the static methods correctly. To partially mock static methods you need to use "mockStaticPartial" and not createPartialMock. The latter is only for instance mocks. 

I've modified the IAXTest so that it pass and it now also demonstrate how to mock the static method InetAddress.getLocalHost().

/Johan
PowerMockTest-iaxtest-fixed.zip
Reply all
Reply to author
Forward
0 new messages