Using JMockit to return the actual instance from the mocked constructor

I considered the following question, and this is not the same as mine:

jMockit: how to expect constructor calls for mocked objects?

This question is similar, but the answer does not help me:

How to make fun of the default constructor of the Date class using JMockit?

I am trying to make moker call the constructor java.util.zip.ZipFile , especially the one that has the java.io.File argument. I would like the constructor to return an instance of another ZipFile , which I will create using a constructor that takes only the String argument.

This constructor call occurs inside the test method, so I cannot insert a ZipFile as a parameter.

For example, the code looks something like this:

 public void whatever() { //some code //some more code foo(); //yet more unrelated code } private Blah foo() { ZipFile zf; //a bunch of code we don't care about zf = new ZipFile(someFile);// I want to give it a known zipfile! mock this! // some more code we don't care about Enumeration<?> entries = zf.entries(); ZipEntry entry = (ZipEntry) entries.nextElement(); InputStream is = zf.getInputStream(entry) //maybe some other calls to the ZipFile // do something else } 

My first thought was to do the following with static partial mockery:

 final ZipFile test = new ZipFile("path/to/actual.zip"); new NonStrictExpectations() { @Mocked("(java.io.File)") ZipFile zf; { new ZipFile((File) any); result = test; } }; 

But this will not work, as indicated in this line in the tutorial: constructors have void return type, so it makes no sense to record return values for them

My second thought was to try the following:

 new NonStrictExpectations() { { newInstance("java.util.zip.ZipFile", new File("path/to/actual.zip")); } }; 

But when you try to initialize the file, this causes the following:

 java.util.zip.ZipException: error in opening zip file at java.util.zip.ZipFile.open(Native Method) at java.util.zip.ZipFile.<init>(Unknown Source) at java.util.zip.ZipFile.<init>(Unknown Source) 

My third thought was to use @MockClass as shown below:

 @Before public void setUp() throws Exception { Mockit.setUpMocks(MockedZipFile.class); } @After public void tearDown() { Mockit.tearDownMocks(); } @MockClass(realClass=ZipFile.class) public static class MockedZipFile { public ZipFile it; @Mock public void $init(File f) throws ZipException, IOException { it = new ZipFile("path/to/actual.zip");//this is what would be called } } 

But these are the hoses for some other layouts that I have, loading the configuration file for another part of my test class. Not to mention that I need different zip files for different test cases.

I suppose I could make fun of everything ZipFile , but it would quickly become a huge pain, because it was called a lot of places, the output would be a mockery, etc. etc. Refactoring to try to make it accessible will be inconvenient, since the code that uses ZipFile is internal to the code, and public methods really don't care about that.

I have a feeling that JMockit allows this to be resolved (by giving a specific instance of the object when the constructor is called), but I cannot figure it out. Does anyone have any ideas?

EDIT: I tried the method suggested by @Rogerio, but I have a new error. Here is my setup:

 final ZipFile test = new ZipFile("path/to/actual.zip"); new NonStrictExpectations() { ZipFile zf; { zf.entries(); result = test.entries(); zf.getInputStream((ZipEntry) any); result = new Delegate() { InputStream getInputStream(ZipEntry entry) throws IOException { return test.getInputStream(entry); } }; } }; 

but I get the following stack trace:

 java.lang.InternalError at path.to.test.ExtractDataTest$1.<init>(ExtractDataTest.java:61) at path.to.test.ExtractDataTest.setUp(ExtractDataTest.java:61) at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:49) at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197) 

where line 61 is the line new NonStrictExpectations() { .

I really want to say, "instead of mocking this object, replace this other object of the same type." Maybe I said it badly.

EDIT2: I figured it should include version numbers: Using Eclipse 3.6.1 Java 1.6.0_26 JMockit 0.999.10

+3
source share
2 answers

JMockit can mock the ZipFile class, but it interferes with loading classes, since the JarFile subclass JarFile used by the JVM all the time (whenever it loads a class from a jar file in the classpath). There is currently no easy way to avoid this intervention (there is a plan to “fix” it, but it will take time).

However, this specific test case is not suitable for a mocking instrument anyway. Instead, I would recommend setting up the test so that it provides the actual zip file with the right content in the right place.

(another edit) I just applied the change to JMockit (for release 0.999.12), which allows you to pass the following test if there is a test.zip file in the working directory and it contains a text file whose first line is "test":

 @Test public void mockZipFile() throws Exception { final ZipFile testZip = new ZipFile("test.zip"); new NonStrictExpectations() { @Capturing @Injectable ZipFile mock; { mock.entries(); result = testZip.entries(); mock.getInputStream((ZipEntry) any); result = new Delegate() { InputStream delegate(ZipEntry e) throws IOException { return testZip.getInputStream(e); } }; } }; ZipFile zf = new ZipFile("non-existing"); ZipEntry firstEntry = zf.entries().nextElement(); InputStream content = zf.getInputStream(firstEntry); String textContent = new BufferedReader(new InputStreamReader(content)).readLine(); assertEquals("test", textContent); } 

However, I would recommend not using the mocking API for such cases. Use a real file instead.

+1
source

This probably won't help you, but if you use Mockito or EasyMock, you can add PowerMock, which allows you to mock the construction of new objects in the test code.

-3
source

Source: https://habr.com/ru/post/1481055/


All Articles