How to get Powermock to work with Dexmaker - java

I am trying to incorporate Powermock as a dependency for my Android tests using the following build.gradle configuration:
dependencies{
compile 'com.android.support:appcompat-v7:21.0.+'
androidTestCompile('org.mockito:mockito-core:1.9.5')
androidTestCompile('com.google.dexmaker:dexmaker:1.2')
androidTestCompile('com.google.dexmaker:dexmaker-mockito:1.2')
androidTestCompile('org.powermock:powermock-module-junit4:1.5.5') {
exclude module: 'junit'
}
androidTestCompile('org.powermock:powermock-api-mockito:1.5.5') {
exclude module: 'mockito-all'
}
}
However, the compiler is complaining that
Error:Gradle: Execution failed for task ':app:packageDebugTest'.
> Duplicate files copied in APK mockito-extensions/org.mockito.plugins.MockMaker
File 1: ~/.gradle/caches/modules-2/files-2.1/com.google.dexmaker/dexmaker-mockito/1.2/b99884a4c6ef6335ba376f79aa79632b2421c17c/dexmaker-mockito-1.2.jar
File 2: ~/.gradle/caches/modules-2/files-2.1/com.google.dexmaker/dexmaker-mockito/1.2/b99884a4c6ef6335ba376f79aa79632b2421c17c/dexmaker-mockito-1.2.jar
Looking into the jar structure, I noticed that both Dexmaker and Powermock declare a MockMaker in mockito-extensions
What is a MockMaker? How do they differ?
And the most important question: Is it possible to get Powermock to work nicely with Dexmaker?
Thanks in advance. Any help would be greatly appreciated.

MockMaker is a glue module that integrates dexmaker with Mockito. It does what's necessary for Mockito to generate concrete classes with Dalvik .dex files instead of JVM .class files.
It's possible that Powermock will work with Dexmaker, but it's unlikely advanced Powermock features will work. In particular, Powermock advertises this:
PowerMock uses a custom classloader and bytecode manipulation to enable mocking of static methods, constructors, final classes and methods, private methods, removal of static initializers and more.
That custom class loader is unlikely to work on dalvikvm.

you can try to put this in your build.gradle, it solved to me the same problem
android{
...
packagingOptions{
exclude 'mockito-extensions/org.mockito.plugins.MockMaker'
}
...
}

I had the same problem and i just found the solution here. It involves a bit of manual work and you will have to modify the jar file yourself.
So what nparihar suggests is the following.
Make backup copy of powermock-api-mockito-1.5.5.jar
Rename powermock-api-mockito-1.5.5.jar to powermock-api-mockito-1.5.5.zip
Unzip powermock-api-mockito-1.5.5.zip
cd powermock-api-mockito-1.5.5/
rm -rf mockito-extensions
jar cf powermock-api-mockito-1.5.5.jar META-INF/ org/
put the new jar in your libs foler.
This solution worked for me. Let me know if it works for you as well.
Also, i can see that we are using the same dependencies. In my case i had to remove manually the hamcrest.jar and the objenesis.jar as there were confilcts.
Hope that helps.

Related

How can Junit test classes detect classes defined in a kotlin file?

I have a Java gradle project in which i'm using a kotlin file to easily define pojo-like classes on one line. However, when i try to start a junit5 test I get a compile error stating that it can't detect any of the classes defined in the kotlin file. I have the kotlin plugin included in the gradle.build file. How do i get the test classes to detect the classes defined in the kotlin file?
Thank you
If you write JUnit5-tests with Gradle, be sure to have something like the following in place in your build.gradle-(or build.gradle.kts)-file, so that Gradle also knows that it should use the JUnit5-platform (compare also JUnit 5 User Guide - Build support - Gradle):
tasks.withType<Test> {
useJUnitPlatform()
}
Moreover also ensure that the annotation you use is the following:
org.junit.jupiter.api.Test
and not the one of JUnit4, i.e. org.junit.Test. If you have that one, you probably want to remove the junit4-dependency altogether.

Mock final class with Mockito 2

I'm removing Powermock from the project I'm currently working on, so I'm trying to rewrite some existing unitary test only with Mockito (mockito-core-2.2.28).
When I run the test, I have the following error:
org.mockito.exceptions.base.MockitoException:
Cannot mock/spy class com.ExternalpackagePath.Externalclass
Mockito cannot mock/spy because :
final class
I know that this question has already been asked (How to mock a final class with mockito, Mock objects calling final classes static methods with Mockito), but I didn't find the answer I'm looking for.
Here is an extract of my code :
public class MyClassToTest extends TestCase {
private MyClass myClass;
#Mock private Externalclass ext; // This class is final, I would like to mock it
#Override
protected void setUp() throws Exception {
MockitoAnnotations.initMocks(this); // <<<< The exception is thrown here
ext = Mockito.mock(Externalclass.class);
}
}
As mentioned in the Mockito documentation (https://github.com/mockito/mockito/wiki/What%27s-new-in-Mockito-2, §Mock the unmockable), I added the org.mockito.plugins.MockMaker file. This is the tree of my project :
project
src
com.packagePath.myPackage
myClass
test
com.packagePath.myPackage
myClassToTest
resources
mockito-extensions
org.mockito.plugins.MockMaker
I also tries to put the "resources" directory in "src", in a subdir called "test", but the result is still the same.
I thought that mocking a final was possible with Mockito v2. Does someone have an idea of what is missing here ?
Thanks!
Weird that your solution seems to work.
According to their documentation on Github it says.
Mocking of final classes and methods is an incubating, opt-in feature. It uses a combination of Java agent instrumentation and subclassing in order to enable mockability of these types. As this works differently to our current mechanism and this one has different limitations and as we want to gather experience and user feedback, this feature had to be explicitly activated to be available ; it can be done via the mockito extension mechanism by creating the file src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker containing a single line:
mock-maker-inline
After you created this file, Mockito will automatically use this new engine and one can do :
final class FinalClass {
final String finalMethod() { return "something"; }
}
FinalClass concrete = new FinalClass();
FinalClass mock = mock(FinalClass.class);
given(mock.finalMethod()).willReturn("not anymore");
assertThat(mock.finalMethod()).isNotEqualTo(concrete.finalMethod());
In subsequent milestones, the team will bring a programmatic way of using this feature. We will identify and provide support for all unmockable scenarios. Stay tuned and please let us know what you think of this feature!
My working structure now looks like this.
I couldn't get it working with the configuration file either; however, the Mockito team is so kind and also provides a pre-configured Mockito artifact that requires no configuration in the target project.
As a convenience, the Mockito team provides an artifact where this mock maker is preconfigured. Instead of using the mockito-core artifact, include the mockito-inline artifact in your project. Note that this artifact is likely to be discontinued once mocking of final classes and methods gets integrated into the default mock maker.
So, if you use Gradle and want to test your Kotlin code, just add this to your project's dependencies:
testCompile 'org.mockito:mockito-inline:2.8.9'
testCompile('com.nhaarman:mockito-kotlin:1.5.0') {
exclude group: 'org.jetbrains.kotlin'
exclude group: 'org.mockito'
}
Well, I found what's wrong here, it maybe useful for other people. My project tree is wrong, I put the org.mockito.plugins.MockMaker in a directory "mockito-extension" directly in "src". This is my tree now:
projet
src
com.packagePath.myPackage
myClass
mockito-extensions
org.mockito.plugins.MockMaker
test
com.packagePath.myPackage
myClassToTest
You seem to have had a classpath issue, just like I did.
Your previous setup would have also worked, but it seems like
project/test/resources
was not in your classpath.
I had the same issue when I tried to run this with IntelliJ. I simply marked the resources directory as a Test Resources Root and it worked fine. Praise the gods of Mockito!
I had the same issue that you described. For me, the solution was to create a file named org.mockito.plugins.MockMaker in /test/java/resources/mockito-extensions/ directory and write the following line: mock-maker-inline.
So MockMaker is actually the file extension (no txt, properties or any other extension needed).
I also encountered the same issue.
This worked for me: How to use the Mockito's inline mock maker: Option 2
Before Mockito can be used for mocking final classes and methods, it needs to be configured. Based on your screenshot of your project tree, it seems that the location of MockMaker file is incorrect.
Create (if the file still does not exist) or update MockMaker file in the path below
src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
... and add this line mock-maker-inline.
If you have multiple modules in project check out if they also have some references to Mockito. For me the problem was deprecated and unnecessary definition in some other small and forgotten library module:
testCompile 'org.mockito:mockito-all:1.10.19'
Removing this unnecessary declaration solved the problem for me
After following configuration instruction, I still wasn't able to get it working.
For me it was due to JDK I was using. After switching to a different one (different provider) the solution with org.mockito.plugins.MockMaker file worked.
I went from JDK with Hotswap agent (trava-jdk-11-dcevm / dcevm-11.0.11+1) to Eclipse adoptOpenJDK (temurin-11.0.14).
This solution worked for me:
Instead of
testCompile "org.mockito:mockito-android:2.9.0"
in the gradle file, replace it with
testCompile group: 'org.mockito', name: 'mockito-inline', version: '2.9.0'
and it would work.

Can I force the order of dependencies in my classpath with Gradle?

A project runs on Google App Engine. The project has dependency that uses a class that can't be invoked on App Engine due to security constraints (it's not on the whitelist). My (very hacky) solution was to just copy a modified version of that class into my project (matching the original Class's name and package) that doesn't need the restricted class. This works on both dev and live, I assume because my source appears in the classpath before my external dependencies.
To make it a bit cleaner, I decided to put my modified version of that class into it's own project that can be packaged up in a jar and published for anyone else to use should they face this problem.
Here's my build.gradle:
// my jar that has 'fixed' version of Class.
compile files('path/to/my-hack-0.0.1.jar')
// dependency that includes class that won't run on appengine
compile 'org.elasticsearch:elasticsearch:1.4.4'
On my local dev server, this works fine, the code finds my hacked version of the class first at runtime. On live, for some unknown reason, the version in the elasticsearch dependency is loaded first.
I know having two versions of the same class in the classpath isn't ideal but I was hoping I could reliably force my version to be at the start of the classpath. Any ideas? Alternatively, is there a better way to solve this problem?
Not really sure if this is what people visiting this question were looking for, but this was what my problem and a solution that I reached at.
Jar A: contains class XYZ
Jar B: also contains class XYZ
My Project needs Jar B on the classpath before Jar A to be able to get compiled.
Problem is Gradle sorts the dependencies based on alphabetical order post resolving them which meant Jar B will be coming after Jar A in the generated classpath leading to error while compiling.
Solution:
Declare a custom configuration and patch the compileClasspath. This is how the relevant portion of build.gradle might look like.
configurations {
priority
sourceSets.main.compileClasspath = configurations.priority + sourceSets.main.compileClasspath
}
dependencies {
priority 'org.blah:JarB:2.3'
compile 'org.blah:JarA:2.4'
...
}
It's the app engine classloader I should have been investigating, not gradle...
App Engine allows you to customise the class loader JAR ordering with a little bit of xml in your appengine-web.xml. In my case:
<class-loader-config>
<priority-specifier filename="my-hack-0.0.1.jar"/>
</class-loader-config>
This places my-hack-0.0.1.jar as the first JAR file to be searched for classes, barring those in the directory war/WEB-INF/classes/.
...Thanks to a nudge in the right direction from #Danilo Tommasina :)
UPDATE 2020:
I just hit the same problem again and came across my own question... This time, live appengine was loading a different version of org.json than was being loaded in dev. Very frustrating and no amount of fiddling the build script would fix it. For future searchers, if you're getting this:
java.lang.NoSuchMethodError: org.json.JSONObject.keySet()Ljava/util/Set;
It's because it's loading an old org.json dependency from god-knows-where. I fixed it by adding this to my appengine-web.xml:
<class-loader-config>
<priority-specifier filename="json-20180130.jar"/>
</class-loader-config>
You'll also need a matching dependency in build.gradle if you don't already have one:
compile 'org.json:json:20180130'
According to gradle dependencies documentation, the order of dependencies defines the order in the classpath. So, we can simply put the libraries in the correct order in "dependencies".
But beware! here are two rules with higher priorities:
For a dynamic version, a 'higher' static version is preferred over a 'lower' version.
Modules declared by a module descriptor file (Ivy or POM file) are preferred over modules that have an artifact file only.

gradle: best way to encapsulate custom dsl

my screencast, i hope my aExtFunc can work in build.gradle in any projects, but intellij idea raise
Cannot resolve symbol 'gradleExt'
my question is: how to fix it.
Defining dependency on the project
dependencies{
compile project(':gradleExt')
}
Doesn't mean that you can work with the content of the project in your build script:
task ATask() {
new gradleExt.Ext().aExtFunc()
}
You probably need to create new groovy class directly in the build.gradle file implementing desired behaviour. Or if you really want to have the implementation in different place you need to add the classpath dependecy into the buildScript{} block. See the documentation on implementing custom tasks:
http://www.gradle.org/docs/current/userguide/custom_tasks.html
If you want custom dsl, then custom gradle plugin is probably what you are looking for
http://www.gradle.org/docs/current/userguide/custom_plugins.html
And also please double check the documentation on multi-project builds if that might be of any use to you, it is not clear from the "my screencast" what your overall gradle setup is. I would post the link, but I don't have enough reputation.

Is it possible to compile a java file without providing its dependencies?

There is a java file, which has some dependencies jars. But now, I don't have those jars, and I have to compile it to a .class file.
Is it possible to do this?
UPDATE
Thanks for your answers.
At first, I thought we can create some stubs for the missing dependencies, that's easy but boring. Since we can create the stubs without missing stubs to make the compiler happy, why can't we make a tool do it automatically? The tool doesn't need to create stubs, but reads the java file, collects informations, and then builds the .class files.
But if the "import" statements in the java file contain "*", that will be a problem:
import aaa.*
import bbb.*
public class Hello {
World world;
}
We don't know if the class "World" is under package "aaa" or "bbb". If we are not familiar with the missing dependencies, we even don't know how to create a stub for the class "World".
But if the "import" statements are clear, I think it's possible, but maybe no one will write such a tool
You could go crazy and hand craft the required dependencies as stubs that do nothing except keep the compiler happy.
No. Sorry. You'll need all dependncies in the classpath to compile.
No. But you could provide stubbed-out versions of the dependency class files, if it is only a handful of classes that the code your are trying to compile uses directly.
Then in theory if you take the .class file that compiles and place the real dependencies on the classpath with it your app will work using the correct (non-stubbed-out) dependency classes.
Before any file is compiled it always looks up for any dependencies.
but you said you dont have those jars!!!
see if you can remove the dependencies relation for that project/file and then try to compile it. give it a try!

Categories

Resources