0

I'm trying to mock an external library, however the actual object created in APKDecompiler is being used, instead of the mock object.

Test code

import com.googlecode.dex2jar.v3.Dex2jar;
import jd.core.Decompiler;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.easymock.PowerMock;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import APKDecompiler;

import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.expectLastCall;
import static org.junit.Assert.assertEquals;
import static org.powermock.api.easymock.PowerMock.*;

import java.io.File;
import java.io.IOException;

@RunWith(PowerMockRunner.class)
@PrepareForTest({Dex2jar.class})
public class TestAPKDecompiler {
   //As this only uses external libraries, I will only test that they are called correctly by mocking them.
    @Test
    public void testAPKDecompiler() {
        try {
            File testFile = new File("ApkExtractor/src/test/resources/testApp.jar");
            String expectedDirectory = testFile.getAbsolutePath().substring(0, testFile.getAbsolutePath().length() - 4);
            mockStatic(Dex2jar.class);
            Dex2jar mockApkToProcess = createMock(Dex2jar.class);
            Decompiler mockDecompiler = createNiceMockAndExpectNew(Decompiler.class);


            expect(Dex2jar.from(testFile)).andStubReturn(mockApkToProcess);

            mockApkToProcess.to(new File(expectedDirectory + ".jar"));
            expectLastCall();

            PowerMock.expectNew(Decompiler.class).andReturn(mockDecompiler).anyTimes();

            expect(mockDecompiler.decompileToDir(expectedDirectory + ".jar", expectedDirectory)).andReturn(0);


            replay(mockApkToProcess);
            PowerMock.replay(mockDecompiler);
            replayAll();
            String actualDirectory = APKDecompiler.decompileAPKToDirectory(testFile);

            verify(mockApkToProcess);
            verify(mockDecompiler);
            verifyAll();

            assertEquals(expectedDirectory, actualDirectory);
            testFile.delete();
        }
        catch(Exception e){
            e.printStackTrace();
        }
    }
}

Class code

import com.googlecode.dex2jar.v3.Dex2jar;
import jd.core.Decompiler;
import jd.core.DecompilerException;

import java.io.File;
import java.io.IOException;

public class APKDecompiler {
    public static String decompileAPKToDirectory(File filename) throws IOException, DecompilerException {
        String filenameWithoutFileExtension = filename.getAbsolutePath().substring(0, filename.getAbsolutePath().length() - 4);
        Dex2jar apkToProcess = Dex2jar.from(filename);
        File jar = new File(filenameWithoutFileExtension + ".jar");
        apkToProcess.to(jar);
        Decompiler decompiler = new Decompiler();

        decompiler.decompileToDir(filenameWithoutFileExtension + ".jar", filenameWithoutFileExtension);

        return filenameWithoutFileExtension;
    }

I've tried this and I haven't had any luck. EasyMock: Mocked object is calling actual method

I get a FileNotFoundException when decompiler.decompileToDir is called, which shouldn't happen as I should be mocking the class.

Any help would be greatly appreciated.

Bigminimus
  • 106
  • 3

1 Answers1

1

The answer was I didn't include the class i was testing in the @PrepareForTest annotation.

@PrepareForTest({APKDecompiler.class, Dex2jar.class, Decompiler.class})
Bigminimus
  • 106
  • 3