android-gradle-aspectj icon indicating copy to clipboard operation
android-gradle-aspectj copied to clipboard

Instrumented tests fails when aspectj plugin is applied

Open ashj11 opened this issue 6 years ago • 17 comments

Preconditions: Application's build.gradle has the aspectj plugin enabled apply plugin: 'com.archinamon.aspectj' Aspects are added to another module( library module ), with the plugin com.archinamon.aspectj-provides applied. This has been configured with includeAspectsFromJar in the app's build.gradle

Problem: When i launch Instrumentation tests my app fails to start due to:

java.lang.ClassNotFoundException: Didn't find class "com.example.MyApp" on path: DexPathList ... Task transformClassesWithAspectjForDebugAndroidTest doesn't get executed correctly, though transformClassesWithAspectjForDebug prints the weaving info correctly.

:transformClassesWithAspectjForDebugAndroidTest
---------- Starting augmentation with AspectJ transformer ----------
Ajc classpath doesn't has needed runtime environment
---------- Exit AspectJ transformer w/o processing ----------

Note that running the application works fine( weaving works too ). Issue is only with Instrumented tests. Though https://github.com/Archinamon/android-gradle-aspectj/issues/72 looks similar, it doesn't provide much insights into the solution. The issue doesn't seem to be related to Java 8.

ashj11 avatar Apr 03 '19 17:04 ashj11

The example project seems to be excluding annotation support for certain dependencies.

androidTestCompile('com.android.support.test:runner:0.5') { exclude module: 'support-annotations' }
androidTestCompile('com.android.support.test:rules:0.5') { exclude module: 'support-annotations' }

I tried doing the same, which didnt help

    androidTestImplementation( "androidx.test:runner:$runner_version" ) {
        exclude module: 'annotation'
    }
    androidTestImplementation( "androidx.test:rules:$runner_version" ) {
        exclude module: 'annotation'
    }

@Archinamon Could you please guide?

ashj11 avatar Apr 04 '19 18:04 ashj11

What version of the gradle dist and android gradle plugin are you trying to apply it with? Do you want to augment androidTest module's code with aj?

Archinamon avatar Apr 07 '19 11:04 Archinamon

Thanks for the reply @Archinamon Gradle plugin version that I am using is 3.2.1( com.android.tools.build:gradle:3.2.1 ). And gradle dist is 4.6 ( distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip ). I don't want the androidTest module's code to get augmented. I just want the source files to get augmented. When i run the connected test with aspectj plugin enabled, it fails to find any test class. Fails with No test found. When plugin is disabled, the tests run correctly. Do I need to do any additional configuration to make this work?

Output ( No tests found)

10:13:32 V/InstrumentationResultParser: INSTRUMENTATION_RESULT: stream=
10:13:32 V/InstrumentationResultParser: 
10:13:32 V/InstrumentationResultParser: Time: 0
10:13:32 V/InstrumentationResultParser: 
10:13:32 V/InstrumentationResultParser: OK (0 tests)
10:13:32 V/InstrumentationResultParser: 
10:13:32 V/InstrumentationResultParser: 
10:13:32 V/InstrumentationResultParser: INSTRUMENTATION_CODE: 0
10:13:32 V/InstrumentationResultParser: 
Starting 0 tests on Pixel_XL_API_27_Wifi(AVD) - 8.1.0

transformClassesWithAspectjForDebug seems to be correct.

> Task :transformClassesWithAspectjForDebug
---------- Starting augmentation with AspectJ transformer ----------
include aspects from :: <path>/build/intermediates/intermediate-jars/debug/classes.jar
Weaving in simple mode
Ajc config: -encoding :: , UTF-8, , -source :: , 1.7, , -target :: , 1.7, , -d :: , <path>d/build/intermediates/transforms/aspectj/debug/0, , -bootclasspath :: , <path>/Android/sdk/platforms/android-28/android.jar:<path>/Android/sdk/platforms/android-28/optional/org.apache.http.legacy.jar, , -classpath :: , [ list files ],
, -inpath :: , [ list files ],
, -aspectpath :: , <path>/aspectj-hooks/build/intermediates/intermediate-jars/debug/classes.jar, , -log :: , <path>/build/ajc-transform.log, , -showWeaveInfo :: 
Detailed log in ajc-transform.log
---------- Finish AspectJ transformer ----------
:transformClassesWithAspectjForDebug spend 4771ms
:transformClassesWithAspectjForDebug spend 4771ms

But transformClassesWithAspectjForDebugAndroidTest fails with the below error

> Task :transformClassesWithAspectjForDebugAndroidTest
---------- Starting augmentation with AspectJ transformer ----------
Ajc classpath doesn't has needed runtime environment
---------- Exit AspectJ transformer w/o processing ----------

ashj11 avatar Apr 09 '19 03:04 ashj11

@Archinamon I have created a demo project to show the issue. https://github.com/ashj11/android-aspectj-demo. Could you please have a look and let me know what I am missing?

ashj11 avatar May 04 '19 17:05 ashj11

Update: If i use com.archinamon.aspectj-junit instead, the connected tests will get executed correctly, but doesn't seem to use/call the aspect. Also, if i include apply plugin: 'com.google.firebase.firebase-perf', then the main activity itself will not be found. I am really looking forward to finding a solution to these two issues, since including compile time weaving will help us improve our performance reporting mechanism. @Archinamon Could you please suggest ?

ashj11 avatar May 05 '19 17:05 ashj11

@Archinamon Any update on this? Aspectj gradle plugin looked really promising for us for performance stats measurement and we would love to use it in our app. We will appreciate any help you can provide.

ashj11 avatar May 21 '19 05:05 ashj11

I have the same issue "java.lang.ClassNotFoundException: Didn't find class ..." when trying to run instrumentation test. I will really appreciate any solution.

alex-tiurin avatar May 27 '19 08:05 alex-tiurin

I had the same issue and investigated the issue a bit deeper. Somehow aspectjrt can't be found in androidTest related classpath, so therefore the aspectj transformer does nothing with androidTest files (do not even copy them to output folders), so therefore the actual test apk contains no classes at all. I did a quick workaround by modifying AspectjTransform.kt file to always copy unprocessed files to output. Here you can find the patch file with the modification: instrumentation_test_patch.zip

It won't allow you to augment androidTest code, but tests will be executed properly.

rmatesz avatar May 27 '19 12:05 rmatesz

@rmatesz thanks for you reply. it's great to start instrumentation tests but i really need to augment androidTest code. i'm trying to create annotation which will be applied inside androidTest code.

alex-tiurin avatar May 27 '19 14:05 alex-tiurin

Thanks @rmatesz. Finally i got some time to debug this and here is my observation.

  • In AspectJTransform.kt, we are checking for aspectj runtime by checking for the existence of the jar by name. There are two cases in this.
  1. In the case of certain plugins like Firebase, they do operate on the jars and provide the extracted class files are input for the next transformation. In this case, though the aspectjrt class files are present in the path, the above check will fail.
  2. In the case of android integration tests, the aspectj runtime doesn't seem to be explicitly passed( not sure why ). But if i bypass the check and still allow it to weave, the weaving seems to be happening just fine. And the test passes.
  3. Even if we remove the hasAjRT check, If the aspectjrt is not genuinely present, then weaving fails with a very clear message to check for aspectrt.jar in the classpath, which seems to be good enough. @Archinamon given point 3, was there any strong reason for adding the jar presence check? If not, can we remove it. https://github.com/Archinamon/android-gradle-aspectj/pull/97

ashj11 avatar Aug 02 '19 09:08 ashj11

hasAjRT has been removed. You could try out the 3.4.0 version.

Archinamon avatar Oct 13 '19 11:10 Archinamon

We've tried the latest 3.4.3 version, and unfortunately the compilation of the instrumented tests still fails. The logs show:

> Task :app:transformClassesWithAspectjForGoogleDebugAndroidTest FAILED
---------- Starting augmentation with AspectJ transformer ----------
Weaving in simple mode
Ajc config: -encoding :: , UTF-8, , -source :: , 1.8, , -target :: , 1.8, , -d :: , ...\build\intermediates\transforms\aspectj\androidTest\google\debug\0, , -bootclasspath :: , C:\Users\...\AppData\Local\Android\Sdk\platforms\android-28\android.jar;C:\Users\...\AppData\Local\Android\Sdk\platforms\android-28\optional\org.apache.http.legacy.jar, , -classpath :: , [ list files ],
, -inpath :: , [ list files ],
, -log :: , ...\build\ajc-transform.log, , -showWeaveInfo :: , -Xlint:adviceDidNotMatch=error :: 
Detailed log in ajc-transform.log

1 error

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':app:transformClassesWithAspectjForGoogleDebugAndroidTest'.
> [error] classpath error: unable to find org.aspectj.lang.JoinPoint (check that aspectjrt.jar is in your classpath)
  Look into ...\build\ajc-transform.log file for details

Caused by: org.gradle.api.GradleException: [error] classpath error: unable to find org.aspectj.lang.JoinPoint (check that aspectjrt.jar is in your classpath)
Look into ...\build\ajc-transform.log file for details
	at com.archinamon.api.AspectJWeaver.detectErrors(AspectJWeaver.kt:165)
	at com.archinamon.api.AspectJWeaver.doWeave$android_gradle_aspectj(AspectJWeaver.kt:144)
	at com.archinamon.api.transform.AspectJTransform.transform(AspectJTransform.kt:182)
	at com.android.build.gradle.internal.pipeline.TransformTask$2.call(TransformTask.java:239)
	at com.android.build.gradle.internal.pipeline.TransformTask$2.call(TransformTask.java:235)
	at com.android.builder.profile.ThreadRecorder.record(ThreadRecorder.java:102)
	at com.android.build.gradle.internal.pipeline.TransformTask.transform(TransformTask.java:230)

And the log file contains:

Thu Nov 07 10:26:37 CET 2019
[error] classpath error: unable to find org.aspectj.lang.JoinPoint (check that aspectjrt.jar is in your classpath)

It seems like the transform task actually runs now, however the weaver that is invoked fails nonetheless since the aspectjrt.jar is still not on the classpath.

kzsolti avatar Nov 07 '19 09:11 kzsolti

@kzsolti Could you try adding classpath 'org.aspectj:aspectjrt:1.9.5' to your buildscript dependencies section. That seems to fix the issue for me.

ashj11 avatar Feb 12 '20 09:02 ashj11

@kzsolti If you are using Java based aspects, then there can be an issue( https://github.com/Archinamon/android-gradle-aspectj/issues/104 ). If you face this then, try using the version 3.4.0. @Archinamon The current issue https://github.com/Archinamon/android-gradle-aspectj/issues/93 can be closed as resolved( this issue has been resolved for me. can wait for @kzsolti also to confirm if this fixes his issue )

ashj11 avatar Feb 12 '20 13:02 ashj11

@kzsolti Could you try adding classpath 'org.aspectj:aspectjrt:1.9.5' to your buildscript dependencies section. That seems to fix the issue for me.

Hi @ashj11, unfortunately this suggestion does not solve the issue I described. I tried it, but we're still getting the same error.

kzsolti avatar Feb 17 '20 13:02 kzsolti

Update: If i use com.archinamon.aspectj-junit instead, the connected tests will get executed correctly, but doesn't seem to use/call the aspect. Also, if i include apply plugin: 'com.google.firebase.firebase-perf', then the main activity itself will not be found. I am really looking forward to finding a solution to these two issues, since including compile time weaving will help us improve our performance reporting mechanism. @Archinamon Could you please suggest ?

Hi,

This works for me:

You can change the plugin implementation depends on the gradle task executed. So in your build.gradle(app) file add this code after last 'apply plugin...':

if (getGradle().getStartParameter().getTaskRequests().toString().contains("AndroidTest") || getGradle().getStartParameter().getTaskRequests().toString().contains("UnitTest")) {
    apply plugin: 'com.archinamon.aspectj-junit'
    aspectj {
        compileTests = true
    }
} else {
    apply plugin: 'com.archinamon.aspectj'
    aspectj {
        compileTests = false
    }
}

mrmar096 avatar Aug 18 '20 11:08 mrmar096

Hi folks! Just an update if anyone is still following this thread: We have finally unblocked our project to be able to migrate to Gradle 6, and so we could update to the latest 4.2.1 version of this plugin as well. The androidTest transformation now seems to be fixed with this combination. I've no idea what change in the plugin resolved this issue for us, but we can finally abandon our fork that had a workaround.

kzsolti avatar Oct 12 '20 13:10 kzsolti