androidTestUtil in a library - android

I have a library that contains test-butler. So in the library I do.
implementation 'com.linkedin.testbutler:test-butler-library:2.1.0'
and in the app consuming this library I do:
androidTestImplementation 'com.github.mylib...'
now I am wondering how I could do the same for androidTestUtil - would like that the dependency:
androidTestUtil 'com.linkedin.testbutler:test-butler-app:2.1.0'
comes via the lib and does not need to be stated in the app.

I don't think this is directly possible unfortunately. The only thing I can think of is having a custom Gradle plugin that the app uses and having the plugin depend on AGP and add the androidTestUtil dependency on the Test Butler app. That seems very unnecessary though, and doesn't really save you much over the app just adding the dependency directly.

Related

What’s the use of the coroutines dependencies on an Android app?

My question is what’s the use of the coroutines dependencies on an Android app?
Specifically the following dependency that is mentioned in the Android Developers site
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9'
(or the newer version 1.6.4)
Seems to me that everything that is related to coroutines, works fine even without this dependency. So what is the purpose of adding this dependency to an Android project?
The rest of the dependencies of the Android project
implementation 'androidx.core:core-ktx:1.8.0'
implementation 'androidx.appcompat:appcompat:1.5.1'
implementation 'com.google.android.material:material:1.6.1'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation "androidx.recyclerview:recyclerview:1.3.0-alpha02"
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
Just for your information: coroutines are already included in libraries:
dependencies {
implementation('androidx.appcompat:appcompat:1.5.1'){
exclude group: 'org.jetbrains.kotlinx', module: 'kotlinx-coroutines-core-jvm'
exclude group: 'org.jetbrains.kotlinx', module: 'kotlinx-coroutines-android'
exclude group: 'org.jetbrains.kotlinx', module: 'kotlinx-coroutines-core'
}
//implementation 'com.google.android.material:material:1.7.0' <- include coroutines
//implementation 'androidx.constraintlayout:constraintlayout:2.1.4' <- include coroutines
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.4'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.0'
}
That's why you see and can use coroutines features.
According to the docs:
This gives you access to the Android Dispatchers.Main coroutine dispatcher and also makes sure that in case of a crashed coroutine with an unhandled exception that this exception is logged before crashing the Android application, similarly to the way uncaught exceptions in threads are handled by the Android runtime.
So if you don't use Dispatchers.Main and don't want exceptions to be logged, you can remove this dependency. And make sure to test the app after removing it.
I'm adding another answer because this is a broader issue with Android libraries in general, not just the coroutines library, so you need to be mindful of it. The libraries you use have their own dependencies, so they pull in certain versions of other libraries that they require.
These additional dependencies are called transitive dependencies, and it's why you can use e.g. LiveData without adding the androidx.lifecycle:lifecycle-livedata-ktx package - it's because something else is pulling in a version of that library, e.g. the activity library. You'll often see these dependency versions mentioned in the changelogs for a library, like this activity one:
Version 1.5.1
July 27, 2022
Dependency update
The Activity library now depends on the Lifecycle 2.5.1.
What this means is using version 1.5.1 of the activity library will pull in version 2.5.1 of the lifecycle libraries. That's the most recent dependency version bump, so that goes for the newer versions of activity too.
But often those transitive dependencies will be outdated - libraries usually won't require new versions of another dependency unless they've made significant changes that require an upgrade. Generally, they're not requiring the most recent versions of other libraries.
This means if you want to use newer versions of those libraries, you need to explicitly add them as dependencies yourself. For a long time, activity would pull in a really old version of lifecycle - if you wanted to use the newer features, you had to import lifecycle yourself, using the version number you wanted. When a dependency is declared multiple times with different versions, Gradle picks the highest version (unless you explicitly take steps to prevent that).
If you want to see the dependency tree for your app, you can run the dependencies Gradle task - it'll show you what dependencies each library requests, their version numbers, and whether they're the version that's ultimately being selected or if they're being superseded by another declaration elsewhere in the tree. You can do that with this button in the Gradle window:
and running gradle app:dependencies (or using gradlew from the command line). There's some info about interpreting the output here.

Gradle module output configuration for test dependencies only

I have a Gradle project containing the two modules app and test, where test contains utilities for testing only. Now I'd like to setup this module, so it doesn't include any outputs into the main configuration of app; even not accidentally.
implementation project(':test') # should fail or not contain any inputs
testImplementation project(':test') # should include all inputs
androidTestImplementation project(':test') # should include all inputs
How do I configure test to behave like this?
I'd assume it would be similarly to how the Android plugin handles configurations for build types and flavors, but I'm also not sure on how to figure this out.
I think these are handled with Gradle consumer attributes. Maybe there's a filter or an attribute which could be applied to it to make it only available to tests.
You could use annotations for that:
https://developer.android.com/studio/write/annotations#visible
Another way would be exclude testing code to new module named as sub_test and use testImplementation or androidTestImplementation of that sub_test module in your test module
Found: Use separate test modules for instrumented tests, which tells the how to do it:
... apply the com.android.test plugin instead of com.android.library.
The java-test-fixtures plugin almost behaves like I wished, just a bit more verbose.
implementation project(':test') # should fail or not contain any inputs
testImplementation testFixtures(project(':test'))
androidTestImplementation testFixtures(project(':test'))
Some other downsides for now
As Tom Tresansky Is the java-test-fixtures plugin incompatible with the Build and run using IntelliJ IDEA setting? asked and answered, the Android Studio doesn't handle the testFixtures source set well.
Also it is not yet available for Kotlin or Android. But as Michael Evans pointed out, there's tasks already open for Android and on YouTrack.
But creating the test fixtures with a Kotlin JVM project and consuming these with an Android project works fine for me.

More than one file was found with OS independent path 'mockito-extensions/org.mockito.plugins.MockMaker'

More than one file was found with OS independent path 'mockito-extensions/org.mockito.plugins.MockMaker' getting this error while adding
androidTestImplementation "org.mockito:mockito-inline:2.15.0"
in gradle to mock final class
For Android, you usually just want
androidTestImplementation "org.mockito:mockito-android:<latest-version>"
You especially don't want mockito-inline because it configures the wrong MockMaker (mock-maker-inline) instead of AndroidByteBuddyMockMaker which is the only one working on Android that is distributed by the Mockito project. If you need advanced capabilities or faster mocking, head over to the dexmaker project.
In my case I resolved this issue by removing dexmaker dependency from the build.gradle
So, I removed the below dependency
androidTestImplementation "com.linkedin.dexmaker:dexmaker-mockito:2.12.1"
and kept only the below Mockito dependency
androidTestImplementation "org.mockito:mockito-android:2.25.0"
Not sure if that your case, but it solves mine.
If you are using Koin dependency injector, I found the solution on this Github issue.
Try androidTestImplementation ("org.koin:koin-test:$koin_version") { exclude group: 'org.mockito' }
It worked for me, I hope this may help others in the future.
The only correct answer is PowerMockito does not support the Davik VM Android uses, it is meant for a standard JVM. So you can't use it with instrumented tests, only unit tests. I have heard there's a library called OpenDex that allows you to use PowerMockito even with Android but it seems a bit involved to setup and I haven't personally tried it.

Library dependency issues with gradle 3.0.0-alphaX

I have a library project with submodules that include many dependencies that I'd like to pass to the developer's application. For example, module A may include all the necessary appcompat dependencies.
With the migration changes, I've updated all compile cases to api, which should not affect anything. However, I no longer have access to any of the libraries dependencies. I can only use code and references from my library itself.
Is there any way around this?
One of the build gradle files of my library submodules can be found here for reference.
The dependencies:
dependencies {
api "org.jetbrains.kotlin:kotlin-stdlib:${KOTLIN}"
api "com.android.support:appcompat-v7:${ANDROID_SUPPORT_LIBS}"
api "com.android.support:support-v13:${ANDROID_SUPPORT_LIBS}"
api "com.android.support:design:${ANDROID_SUPPORT_LIBS}"
api "com.android.support:recyclerview-v7:${ANDROID_SUPPORT_LIBS}"
api "com.android.support:cardview-v7:${ANDROID_SUPPORT_LIBS}"
api "com.android.support.constraint:constraint-layout:${CONSTRAINT_LAYOUT}"
api "com.mikepenz:iconics-core:${ICONICS}#aar"
api "com.mikepenz:google-material-typeface:${IICON_GOOGLE}.original#aar"
api "com.afollestad.material-dialogs:core:${MATERIAL_DIALOG}"
api "com.jakewharton.timber:timber:${TIMBER}"
api "org.jetbrains.anko:anko-commons:${ANKO}"
}
Edit:
To clarify, the sample project in the module actually does build properly, but there's an issue with using the dependencies in any other app, where it pulls from jitpack. See this gradle as an example that won't build.
I've tried using combinations of api, implementation, #aar, and transitive.
Come to think of it, this may be a jitpack issue and not a gradle issue, but if anyone else has a resolution I'd like to hear it.
I no longer have access to any of the libraries dependencies. I can only use code and references from my library itself.
It is correct.
From the gradle docs :
dependencies {
api 'commons-httpclient:commons-httpclient:3.1'
implementation 'org.apache.commons:commons-lang3:3.5'
}
Dependencies appearing in the api configurations will be
transitively exposed to consumers of the library, and as such will
appear on the compile classpath of consumers.
Dependencies found in the implementation configuration will, on the
other hand, not be exposed to consumers, and therefore not leak into
the consumers' compile classpath. This comes with several benefits:
dependencies do not leak into the compile classpath of consumers anymore, so you will never accidentally depend on a transitive
dependency
faster compilation thanks to reduced classpath size
less recompilations when implementation dependencies change: consumers would not need to be recompiled
cleaner publishing: when used in conjunction with the new maven-publish plugin, Java libraries produce POM files that
distinguish exactly between what is required to compile against the
library and what is required to use the library at runtime (in other
words, don't mix what is needed to compile the library itself and what
is needed to compile against the library).
The issue seems to be related to the android-maven-gradle-plugin
Issue Report
It's has been fixed in version "2.0" of android-maven-gradle-plugin
just update to
dependencies {
classpath 'com.github.dcendents:android-maven-gradle-plugin:2.0'
}
or using the new syntax since Gradle 2.1
plugins {
id "com.github.dcendents.android-maven" version "2.0"
}
using api in your library module allows you to access the transient dependencies only in your library code; not the apps that consume it.
so to achieve the desired effect you need to change in your sample module.
implementation project(':core')
to
api project(':core')
note you don't need to use api in your library it's better to use implementation as it speeds up your build.

What is "implementation" in Kotlin Gradle dependencies?

I'm using Android Studio 3.0 Preview to start new Kotlin project. As I try to add dependencies in build.gradle I saw implementation scope instead of usual compile.
androidTestImplementation('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
implementation 'com.android.support:appcompat-v7:25.3.1'
testImplementation 'junit:junit:4.12'
There's also androidTestImplementation and testImplementation scope.
In the end, I add compile to add third party dependencies and it works.
compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
So my questions are..
What is implementation, androidTestImplementation, and testImplementation scope?
Is it any different than compile, testCompile, and androidTestCompile?
Which one I should use for my Kotlin project?
Edit:
My bad, this question is not Kotlin specific. It's the new Android Gradle Plugin configuration.
This is not specific to Kotlin, but has to do with the new Gradle plugin for Android.
compile, provided and apk are now deprecated.
Use implementation or api instead of compile, compileOnly instead of provided, and runtimeOnly instead of apk.
The reason for this is to speed up multi-module builds. Given module A which depends on module B which in turn depends on module C, a change in module C would trigger a recompile of module A as well. If A does not use C directly, there is no need for A to recompile when C changes.
The implementation configuration ensures exactly this: if you specify implementation project(':C') in B, you cannot access C from A and you avoid building unnecessary modules. In a large multi-module project this can save a lot of time.
See Migrate to the new Gradle plugin for more information.
Earlier version of gradle v3.0.0-alpha1 used to use compile but it has been deprecated now on.
Why?
Dependencies appearing in the compile configurations will be transitively exposed to consumers of the library, and as such will appear on the compile classpath of consumers. Dependencies found in the implementation configuration will, on the other hand, not be exposed to consumers, and therefore not leak into the consumers' compile classpath.
Let's take an example to understand this. Let's say, I created a Library_Image_Upload that supports Image uploading to the server. I used Library_Network lib in Library_Image_Upload that supports all the network operations. My library only makes use of image uploads and provide a convenient way of uploading images. Now as i used Library_Network lib in my Library_Image_Upload project, everyone using this lib will have functionality of Image Uploading along with all network operations that someone may also use(Important). Later on i thought there is a better alternative to Library_Network as Library_Magic_Image and used it. So all the API functions exposed by Library_Network are gone and whoever is using those functions has broken build.
implementation comes with several benefits:
Dependencies do not leak into the compile classpath of consumers anymore, so you will never accidently depend on a transitive dependency
Faster compilation thanks to reduced classpath size
Less recompilations when implementation dependencies change: consumers would not need to be recompiled
Cleaner publishing: when used in conjunction with the new maven-publish plugin, Java libraries produce POM files that distinguish exactly between what is required to compile against the library and what is required to use the library at runtime (in other words, don't mix what is needed to compile the library itself and what is needed to compile against the library).
To learn more read The Java Library Plugin
So i think you have the answer of all three questions.
I hope it helps.

Categories

Resources