I'm having trouble creating a unit test without needing robolectric. I am using AndroidThreeTen.init(this) in my code and when I run my test if I disable robolectric I get an error:
org.threeten.bp.zone.ZoneRulesException: No time-zone data files registered
and if I leave it enabled I get this:
[Robolectric] com.mycomp.,yapp.utilities.log.LogTest.on Calling function w it returns an Int: sdk=28; resources=BINARY
I have tried using testImplementation ‘com.jakewharton.threetenabp:threetenabp:1.1.0’
made no difference. I have AndroidThreeTen.init(this) called in my application and testApplication. any ideas?
this is my test
#Test
fun `on Calling function i it returns an Int`() {
assertThat("Returned class is not an Int", Log.i("Test", "Test"), isA(Int::class.java))
assertThat("Returned Int is not 0", Log.i("Test", "Test"), `is`(0))
}
Or do I have to use robolectric because of this?
(Side note: Log is not the util.log from android but my own class) (edited)
JVM unit tests don't run on Android runtime. Instead of ThreeTenABP, you can just use ThreeTenBP directly to get the same API initialised for a regular JVM.
In my project build.gradle I use a setup like:
implementation "com.jakewharton.threetenabp:threetenabp:${threetenabpVersion}"
testImplementation("org.threeten:threetenbp:${threetenbpVersion}") {
exclude module: "com.jakewharton.threetenabp:threetenabp:${threetenabpVersion}"
}
where
threetenabpVersion = '1.2.0'
threetenbpVersion = '1.3.8'
This uses ThreeTenBP via ThreeTenABP normally, but in unit test configuration it adds TreeTenBP directly as a dependency, with its init code. Cannot remember exactly why I put in the exclude rule; it's been like that for a few years already.
For some reason #laalto solution didn't work for me. Here's what worked instead:
dependencies {
...
implementation "com.jakewharton.threetenabp:threetenabp:$threetenabp_version"
testImplementation "org.threeten:threetenbp:$threetenbp_version"
}
configurations.testImplementation {
exclude group: 'com.jakewharton.threetenabp'
}
Related
In pursuit of "write once, run anywhere" integration tests, I am trying to move my test helpers into a Gradle module that can be included via testImplementation or androidTestImplementation. This helper module contains Espresso actions and assertions, which depend on View IDs and String resource identifiers from my app.
The problem -- When my helper module is included via androidTestImplementation, the module's resource references are only resolvable with the test context InstrumentationRegistry.context, rather than my app's InstrumentationRegistry.targetContext.
Is this expected? How else could I share resource reference-containing code between test and androidTest contexts, such that references always resolve to the target app context?
Sample code:
// :sharedtest Gradle module script
// Imports features in order to pull in their resource IDs
implementation(project(":features1"))
implementation(project(":features2"))
...
// Kotlin helpers inside :sharedtest Gradle module
import com.myapp.sharedtest.R
fun clickInsights() {
onView(withId(R.id.insights_tool)).perform(click())
}
...
// Integration test inside :app which
// includes :sharedtest module via androidTestImplementation
#Test
fun verifyClickInsights() {
// fails because com.myapp.sharedtest.R.id.insights_tool is not resolved as expected
clickInsights()
}
...
I explored Test Fixtures to house my test helpers, but seems AGP doesn't support them for Android Kotlin code at this time. I also considered source sets, but those have been deprecated in favor of Gradle modules.
I found success in changing my sharedtest helper imports to be child-module relative, i.e. com.myapp.feature1.R works, but com.myapp.sharedtest.R doesn't. But I'd like to
A) understand why this works and
B) avoid it if possible, since using sharedtest references everywhere is simplest codewise.
I work on an Android project using multiple Project Flavors, and we use Koin to inject the appropriate dependencies based on the current flavor.
We already use the checkModules Gradle task (described here : https://start.insert-koin.io/#/getting-started/testing?id=checking-your-modules) in order to ensure that our dependency tree is valid.
However, it seems that there is a use case missing.
Let's say I want to inject an InterfaceA in my Activity. I would write the following code :
class MyActivity : Activity() {
private val interfaceA_Impl: InterfaceA by inject()
...
}
Koin requires the implementation of InterfaceA to be provided in a module, as such :
val myModule = module {
single<InterfaceA> { MyInterfaceImpl() }
}
In my project, each implementation is "flavor-specific".
My question is :
Is there a way to ensure that ALL by inject targets are valid ? In other words, to ensure that all interfaces that I am trying to inject have valid implementations ? Currently, if an implementation is forgotten, the app crashes during runtime, and I would like to know about it sooner (maybe during unit tests, at the same time checkModules is ran ?)
Thanks a lot !
I am trying to write a Robolectric test. I was following few tutorials where they seem to be using
#RunWith(RobolectricTestRunner::class)
#Config(constants = BuildConfig::class)
to setup the test, but in my case The parameter constants does not seem to resolve.
My Robolectric dependency looks like this:
testImplementation "org.robolectric:robolectric:4.0.2"
constants parameter is now deprecated see the doc :
constants
Deprecated.
If you are using at least Android Studio 3.0 alpha 5 please migrate to the
preferred way to configure builds for Gradle with AGP3.0
http://robolectric.org/getting-started/
The proper way to set up Robolectric per the documentation is :
android {
testOptions {
unitTests {
includeAndroidResources = true
}
}
}
dependencies {
testImplementation 'org.robolectric:robolectric:4.1'
}
Robolectric is for unit test, not for androidTest, so please confirm that your test case is under src/test, NOT under src/androidTest.
I'm trying to replace my Espresso registerIdlingResources and unregisterIdlingResources deprecated method by using IdlingRegistry method according to Android documentation.
Some of my tests worked before the update and no longer work now. These tests work unitarily, but not together.
I noticed that there is a little difference with the old version (of Espresso class), this line is not present in IdlingRegistry class :
baseRegistry.sync(IdlingRegistry.getInstance().getResources(), IdlingRegistry.getInstance().getLoopers());
I think this sync method is very important for my custom IdlingResource...
How can I sync my looper without this line?
Edit: I use EspressoCore 3.0.1 with runner/rules 1.0.1
Edit2: Link of documentation who has been specify deprecation : Here and Here.
Be sure to run the latest version of androidx.test
If your tests run one at a time, but fail when run together, Android Test Orchestrator ("ATO") can solve that problem.
ATO runs each test method in a new process, so any in memory state is cleared.
From the docs, the basic gradle setup is:
android {
defaultConfig {
...
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
// The following argument makes the Android Test Orchestrator run its
// "pm clear" command after each test invocation. This command ensures
// that the app's state is completely cleared between tests.
testInstrumentationRunnerArguments clearPackageData: 'true'
}
testOptions {
execution 'ANDROIDX_TEST_ORCHESTRATOR'
}
}
dependencies {
androidTestImplementation 'androidx.test:runner:1.3.0'
androidTestUtil 'androidx.test:orchestrator:1.3.0'
}
The docs also include setup for installing and using Android Test Orchestrator without gradle.
You can also use ATO on Firebase Test Lab:
via web UI
via CLI
If you still have problems with your IdlingResources you can try the busybee library which simplifies using IdlingResources and makes them easier to debug.
(disclaimer, I am a maintainer of that library)
I have an android project with unit and integration tests in the same folder. If I run ./gradlew test all of them are run, but I just need to exclude the cucumber tests from running, at the moment I just need to actually exclude to run the class with the annotation #RunWith(Cucumber.class).
Any suggestions?
The usual way of adding a test closure like below does not work for some reason with gradle android plugin:
test {
exclude 'com/example/MyTest.*'
}
Instead I have found the following option. Use the #Ignore annotation on your test(s). You can also conditionally ignore the test (e.g. based on a system property like RUN_AUTOMATION_TEST=false) using this answer
If you are using spock rather than junit then use something like this:
#IgnoreIf( {System.getProperty('RUN_AUTOMATION_TESTS') == null} )
public class MainScreenSpec extends BaseUiAutomationSpec {
}