0
votes

I have a junit test that tries to fake Paths.get(String pathStr) using MockUp() and @Mock Path get(String pathStr) that returns a @Mocked Path path; In JMockit 1.23 and 1.22 this worked fine, but starting with JMockit 1.24 and up to 1.28 it's throwing a mockit.internal.ClassFile$NotFoundException and the class it's refering too is TestClassName$2

    new MockUp<Paths>() {
        @Mock
        public Path get(String first, String... more) {
            return path;
        }
    };

Each update to JMockit seems to remove functionality, but I really have no idea what is the cardinal sin here.

UPDATE: I know now that the MockUp is a red herring and the issue is that the Expectations block is not created as an anonymous inner class. I have no idea why.

UPDATE: Code to reproduce:

package foo;

import mockit.Expectations;
import mockit.Mock;
import mockit.MockUp;
import mockit.Mocked;
import org.junit.Test;

import java.io.File;
import java.nio.file.Files;
import java.nio.file.LinkOption;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.Duration;

import static org.hamcrest.core.Is.is;
import static org.hamcrest.core.IsEqual.equalTo;
import static org.junit.Assert.assertThat;

public class ReproJMockitBug {

    private Duration foo(File file, Path path, Duration duration) {
        final boolean exists = Files.exists(path);
        if (!exists && Paths.get("").equals(path)) {
            System.out.print(file.getAbsolutePath());
            return duration.plusMinutes(1);
        }
        return duration;
    }

    @Test
    public void shouldReturnErrorForInvalidFilePath(@Mocked Duration duration, @Mocked File file, @Mocked Path path) {
        String pathStr = "/some/test";

        new MockUp<Paths>() {
            @Mock
            public Path get(String first, String... more) {
                return path;
            }
        };

        new MockUp<Files>() {
            @Mock
            public boolean exists(Path path, LinkOption... options) {
                return false;
            }
        };

        new Expectations() {{
            onInstance(duration).plusMinutes(1);
            result = Duration.ofMinutes(3);
            onInstance(file).getAbsolutePath();
            result = pathStr;
        }};

        assertThat(foo(file, path, duration), is(equalTo(Duration.ofMinutes(3))));
    }

}
2
Could you show a failing test? For me, the mockup for Paths is working fine on JMockit 1.28. - Rogério
@Rogério So, I just filed a bug for this in Github, the issue is that the Expectations block is not found by the class loader (hence the TestClassName$2). I wish I could be more helpful, but I can't provide reproducible code in a timely manner. Maybe in my free time I'll try to reproduce, but I already spent way too much time on it and we are fine staying at 1.23. All I know is that the Expectations anonymous inner class cannot be found and it works in 1.23 but not 1.24 when you made quite a few changes to the ClassFile verification code. - Novaterata
@Rogério I've added code to reproduce - Novaterata
The problem disappears if I remove the @Mock File file from the equation - Novaterata
Some food for thought: 1) the test is seriously abusing the mocking/faking APIs; 2) the test name is very unclear - where's the supposed "invalid path", etc.?; 3) the scenario the test is attempting to verify is impossible, since the empty path ("") corresponds to the default directory (aka the "current working dir"), which always exists - therefore the if block in foo will never be entered (when running "for real"). Or am I missing some weird corner case? - Rogério

2 Answers

2
votes

Here is a much simpler reproducer test:

@Test
public void issue350Reproducer(@Mocked File file) {
    new MockUp<Runnable>() {};
}

So, the use of Expectations is irrelevant. The actual bug is in the mocking of File.

-1
votes

Don't use @Mocked File file outside any test method, use as local mocked like this

   @Test
    public void youMethodName(@Mocked File file) {
        new MockUp<Runnable>() {
{
         b;
         result=file;
}
    };
    }