Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Injectable and Mock static methods of the same class #1

Closed
ColinHebert opened this issue Jul 11, 2014 · 7 comments
Closed

Injectable and Mock static methods of the same class #1

ColinHebert opened this issue Jul 11, 2014 · 7 comments
Assignees

Comments

@ColinHebert
Copy link

This test used to work with JMockit 1.8, stopped working with JMockit 1.9

public class InetAddressTest {
    @Injectable
    private InetAddress mockInetAddress;

    @Test
    public void testInetAddressMock() throws Exception{
        new NonStrictExpectations(InetAddress.class) {{
            InetAddress.getLocalHost();
            result = mockInetAddress;
        }};

        Assert.assertSame(InetAddress.getLocalHost(), mockInetAddress);
    }
}

The problem here is that JMockit complains about the class being already mocked.

Class is already mocked: class java.net.InetAddress

This is fair enough, but what is the recommended approach when I need to mock a static method from a class while having an Injectable value as well?

@rliesenfeld
Copy link
Member

You can write the test with @Cascading, which is simpler:

public class InetAddressTest {
@Cascading
private InetAddress mockInetAddress;

@Test
public void testInetAddressMock() throws Exception {
    Assert.assertSame(InetAddress.getLocalHost(), mockInetAddress);
}

}

That said, not mocking InetAddress would be better, if that's an option.

On Fri, Jul 11, 2014 at 8:39 PM, Colin Hebert notifications@github.com
wrote:

This test used to work with JMockit 1.8, stopped working with JMockit 1.9

public class InetAddressTest {
@Injectable
private InetAddress mockInetAddress;

@Test
public void testInetAddressMock() throws Exception{
    new NonStrictExpectations(InetAddress.class) {{
        InetAddress.getLocalHost();
        result = mockInetAddress;
    }};

    Assert.assertSame(InetAddress.getLocalHost(), mockInetAddress);
}

}

The problem here is that JMockit complains about the class being already
mocked.

Class is already mocked: class java.net.InetAddress

This is fair enough, but what is the recommended approach when I need to
mock a static method from a class while having an Injectable value as
well?


Reply to this email directly or view it on GitHub
#1.

@ColinHebert
Copy link
Author

I'd love to not mock InetAddress, the problem is, InetAddress.getLocalHost().getCanonicalHostName() in Java does a lookup on the hostname which may take quite some time (or even fail) depending on some network settings. To make sure this is handled properly by the application I do not have a better solution right now.

@ColinHebert
Copy link
Author

Regarding the solution itself, my bad I should have given a more detailed example of what I need:

public class InetAddressTest {
    @Injectable
    private InetAddress mockInetAddressLocal;
    @Injectable
    private InetAddress mockInetAddressRemote;

    @Test
    public void testInetAddressMock() throws Exception {
        new NonStrictExpectations(InetAddress.class) {{
            InetAddress.getLocalHost();
            result = mockInetAddressLocal;
            InetAddress.getByName("bing.com");
            result = mockInetAddressRemote;
        }};

        Assert.assertSame(InetAddress.getLocalHost(), mockInetAddressLocal);
        Assert.assertSame(InetAddress.getByName("bing.com"), mockInetAddressRemote);
        Assert.assertNotSame(InetAddress.getByName("bing.com"), InetAddress.getLocalHost());
        // This is doing an actual resolution, not using any mocks.
        Assert.assertEquals(InetAddress.getByName("reddit.com").getCanonicalHostName(), "reddit.com");
    }
}

In this case, the resolution to reddit.com still works with the default behaviour (using 1.8), which is perfect as it's exactly what I need. The problem with mocking classes such as InetAddress is that some subsystems might depend on it, so the less modifications to the default behaviour, the better.

EDIT: changed google.com to reddit.com (google tends to have servers with different hostnames), that doesn't change the point though.

@rliesenfeld
Copy link
Member

This is a tough one.

If the duplicate mocking of InetAddress is allowed, then what to make of a call to "mockInetAddressRemote.getCanonicalHostName()"? Should it be mocked according to the @Injectable mocking, or according to the partial mocking? In the first case, this method call would simply return null without doing anything; in the second, it would execute the real implementation of "getCanonicalHostName()", since no expectation was recorded for it.

Incidentally, I noticed that if that call is made using JMockit 1.8, a JVM crash occurs! I will need to investigate it later.

@ColinHebert
Copy link
Author

I would expect the first behaviour. The @Injectable behaviour should take precedence over the partial mocking (so null as a result).
Not because it fits my use case, but because I would expect @Injectable to be considered as "more specific" (applies to one instance) whereas partial mocking (or @Mocked for that matter) is more broad (applies to the entire class).

@rliesenfeld
Copy link
Member

Yes, it makes more intuitive sense, except that partial mocking is applied later during the execution of the test, so pre-JMockit 1.9 it would always override the @Injectable mocking.

I am considering changing the semantics in cases like this, so that instance methods already mocked through an @Injectable are disregarded if the same class is partially mocked later in the test. But it needs more thinking; an idea that occurs is that the use of a "MockUp" may be a better choice here.

@rliesenfeld
Copy link
Member

The current semantics will be changed so that @Injectable instances are unaffected by an eventual partial mocking of the same class.

rliesenfeld added a commit that referenced this issue Jul 20, 2014
… unaffected, if there are any of the same class. Fixes issue #1.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

No branches or pull requests

2 participants