GithubHelp home page GithubHelp logo

fknives / android-tutorial-test-showcase Goto Github PK

View Code? Open in Web Editor NEW
6.0 1.0 2.0 1.09 MB

Mock project showcasing testing on Android. It is used as a CodeKata.

License: Apache License 2.0

Kotlin 96.03% Java 3.93% Shell 0.05%

android-tutorial-test-showcase's Introduction

Android Test Showcase

License

Mock project showcasing testing on Android. I plan to use this as a CodeKata to experiment with testing.

Disclaimer: Every test you see in this project you should take with a pinch of salt, this is my self-taught experimentation of Testing on Android

Project Overview

The project uses mock api and is really bare bone. It's used just to showcase example features I usually encounter on Android.

You can login with any credentials, mark favourite content items, log out and that's about it.

As dependency injection / Service Locator koin is used.

The application is separated into different modules each module is tested differently.

Modules

Model

Self explanatory, contains all shared data classes (POJOs) and Exceptions used by the other modules. There is nothing to test here.

App

The android module of the application, contains the UI (Activities), Room-Database and ViewModels.

The UI is strucured in MVVM.

Has dependency on the core module and only on core module.

There are 3 kinds of tests in this module:

  • junit5 tests for ViewModels and Dependency Injection
  • Robolectric Test for Room Database and SharedPreferences
  • Shared Tests for Screens (shared between Robolectric and AndroidTests)
  • End to End Android Tests

Unit tests

Verify the ViewModels are reacting to the mocked UseCases properly.

Kotlin-Mockito is used to mock out UseCases comming from the core module.

Koin-Test is used to verify the ServiceLocator modules.

LiveData-Testing is used to verify the LiveData values of ViewModels.

Robolectric

Verifies the DataBase interactions and also verifies the interactions on each Screen.

Robolectric website link.

In Unit and Robolectric tests coroutine-test is used to switch out the mainThread thus enabling fine control over interactions.

AndroidTest

Verifies the interactions with the Screens.

In Robolectric and AndroidTests Espresso is used to interact with UI.

In Robolectric and AndroidTests OkhttpIdlingResources is used to synchronize OkHttp with Espresso.

In Robolectric and AndroidTests Mock Server module is used to mock the network requests.

In Robolectric and AndroidTests InstantTaskExecutor is used to set LiveData values immediately and a Custom implementation in Unit tests.

Core

Business layer of the application. Contains Repositories and UseCases.

Has dependency on the network module. Database/SharedPreferences LocalStorage classes are injected into the core module.

All tests are junit5 and they are using Kotlin-Mockito to mock all dependencies.

Coroutine-test is also used in every test. Turbine is used to test flows, but tests will be shown without turbine as well.

The tests are verifying the interactions between the RemoteSource and LocalSource components. It also verifies that ErrorHandling is done properly.

Has also Integration tests which verify multiple components working together, for this Mock Server module is used to mock responses.

Networking

As the name suggests this is the module which sends requests to the Backend and parses the responses received. All responses and requests are mapped to and from models from the model data classes.

Retrofit + OkHttp + Moshi is used to send and parse requests.

All tests are Junit5. The Retrofit Services are injected into tests to make sure the parsing and other setups are proper.

The tests are verifying all the requests contain the correct arguments, headers, path, methods. It is also responsible to verify the responses are parsed properly.

Mock Server module and MockWebServer is used to respond to the requests sent by OkHttp. JsonAssert is used to compare JSON models.

Mock Server

This module is not actually part of the APK. This module is only used to unify mocking of Network request between Instrumentation tests from app module, core integration tests and network module.

It contains a way to setup responses to requests in a unified way. Contains all Response.json and expected Request.json files.

MockWebServer is used to respond to the requests sent by OkHttp. JsonAssert is used to compare JSON models. OkHttp-TLS is used to have HTTPS requests on Android Tests.

Example Case

This folder contains examples of specific cases such as NavController testing.


Server

The actual server when running the application is mockapi.io so don't expect actual functionalities in the application.

Code Kata

This section describes what you need to play with the exercises in the project.

Code Kata details

Preparation

Download the project, open it in Android Studio.

  • In the gradle window you can see in the root gradle there is a "tests" group. In this group you will see a jvmTests, robolectricTests and androidTests task.
  • First run the jvmTests.
  • When that finished, build the application to your phone.
  • Login with whatever credentials and look over the app, what will you test.
  • When finished, run androidTests.

This will ensure the testing setup is proper, the project can resolve all the dependencies and such issues won't come up during your exercise.

Structure

The Code Kata is structured into 6 different section, each section in different what we are testing and how we are testing it.

Since our layering is "app", "core" and "networking", of course we will jump right into the middle and start with core.

Core

Open the core instruction set.

The core tests are the simplest, we will look into how to use mockito to mock class dependencies and write our first simple tests.

We will also see how to test flows.

Networking

Open the networking instruction set.

The networking instruction set will show you how to test network request with mockwebserver.

It will also show you that you can write tests not only for one class mocking all the dependencies, but a component.

App ViewModel Unit Tests

Open the app viewModel unit tests instruction set.

This section we will see how to replace the dispatcher to testDispatcher to control the ViewModel's coroutines.

We will also see how to test with LiveData.

We will introduce Rules, aka easy to reuse "Before" and "After" components.

Core Again (Integration)

Open the core again instruction set.

We complicate things here. We write our first Integraiton Test. We will verify the Authentication classes and the networking module is working together like a charm.

App Robolectric Unit Tests.

Open the app robolectric unit tests instruction set.

In this section we will see how to test component depending on context such as Room database. In this tests we will also see how to interact with View components in tests via Espresso. We will also see how to test a specific Activity (same concept can be applied to fragments)

Bonus:

Robolectric and Android Tests.

Open the shared tests instruction set.

In this section we will see how can we share Robolectric test source with AndroidTests to run our same tests on actual device. We will also see how to write AndroidTest End to End Tests.


Util classes

Additional modules have been added prefixed with test-util.

These contain all the reusable Test Util classes used in the showcase.

The Testing setup is extracted into a separate gradle script, which with some modifications, you should be able to easily add to your own project.

To use the TestUtil classes, you will need to add the GitHub Repository as a source for dependencies:

See details
// top level build.gradle
allprojects {
    repositories {
        // ...
        maven {
            url "https://maven.pkg.github.com/fknives/AndroidTest-ShowCase"
            credentials {
                username = project.findProperty("GITHUB_USERNAME") ?: System.getenv("GITHUB_USERNAME")
                password = project.findProperty("GITHUB_TOKEN") ?: System.getenv("GITHUB_TOKEN")
            }
            // https://docs.github.com/en/github/authenticating-to-github/keeping-your-account-and-data-secure/creating-a-personal-access-token
        }
    }
}
// OR
// top level build.gradle.kts
allprojects {
    repositories {
        // ...
        maven {
            url = uri("https://maven.pkg.github.com/fknives/AndroidTest-ShowCase")
            credentials {
                username = extra.properties["GITHUB_USERNAME"] as String? ?: System.getenv("GITHUB_USERNAME")
                password = extra.properties["GITHUB_TOKEN"] as String? ?: System.getenv("GITHUB_TOKEN")
            }
            // https://docs.github.com/en/github/authenticating-to-github/keeping-your-account-and-data-secure/creating-a-personal-access-token
        }
    }
}

Latest version:Latest release

and then you can use the following dependencies:

testImplementation "org.fnives.android.testutil:android-unit-junit5:<latestVersion>"   // test-util-junit5-android
testImplementation "org.fnives.android.testutil:shared-robolectric:<latestVersion>"    // test-util-shared-robolectric
testImplementation "org.fnives.android.testutil:android:<latestVersion>"               // test-util-android
androidTestImplementation "org.fnives.android.testutil:android:<latestVersion>"        // test-util-android
androidTestImplementation "org.fnives.android.testutil:shared-android:<latestVersion>" // test-util-shared-android

Code Coverage Report

For Code Coverage Reporting, Jacoco is used.

See details

For Code Coverage Reporting, Jacoco is setup in jacoco.config.gradle.

  • Each sub module has it's own code coverage report, enabled by the gradle script.
  • Additionally it contains gradle task for an aggregated code coverage report for the project as a whole.

Feel free to use that script and tweak it for your project and module setup.

The script is documented, to the best of my understanding, but specific to this project, not prepared for multiple buildFlavours or different buildTypes than debug.

Sub module reports

To run tests and Jacoco report for a submodule, run task jacocoTestReport:

  • for java it will run unit tests and creates a report
  • for android it will run jacocoAndroidTestReport and jacocoUnitTestReport and create 2 separate reports.

Note:

  • jacocoAndroidTestReport is alias to createDebugAndroidTestCoverageReport
  • jacocoUnitTestReport is alias to createDebugUnitTestCoverageReport

Aggregated reports

To see an aggregated code coverage report:

  • task jacocoRootReport will pull together all the submodules report and create a single one from them ($projectDir/build/coverage-report).
  • task runTestAndJacocoRootReport will run all the sub modules reports and tests then run jacocoRootReport.

Issues

  • One issue, is that the androidTest reports don't work with the sharedTest module setup, this issue is reported here
  • Another issue, is that seems like the tests fail with Resource.NotFound on API 21 if enableAndroidTestCoverage is true, so I disabled that for CI.

By shared test module setup I mean a module like app-shared-test, which has a dependency graph of:

  • app-shared-test -> app.main
  • app.test -> app-shared-test

Reference

Here are the two articles I used for the jacoco setup script: jacoco-in-android aggregate-test-coverage.


Screenshot Testing

Screenshot testing example is not present in the repository, but here are my findings regarding the topic.

See details

Screenshot testing can be valuable in a large project. The basic idea is that you have reference screenshots of screens / components which you check once manually. Based on these references you can verify that your changes did not modify other parts of the UI.

Comparision

There are other people who already compared most of the libraries I found. Here are the list of valuable resources that go into more detail than I am doing here.

  • article and repo Comparing multiple solutions.
  • Compose native sample
  • Showkase library, that helps visualise your Compose previews. Can be integrated with screenshot testing as described here
  • Cookbook

Libraries

So here is a list of libraries I found that can be used for this purpose.

This library creates images from your views inflated in your Instrumented Test classes. Can be used with activities launched as well.

Compose Support: Inside activites, yes. As component no.

Learn More


Build on top of Facebook's screenshot tests, has all it's capabilities, Additionally generates side by side comparision when verifying.

Compose Support: Yes.

Learn More


Extends ActivityTestRule and enables taking screenshots of your activities. Has extension for full screen, compose and accssibility!

Compose Support: Yes.

Learn More


Takes screenshots on the device and compares them to asset bitmaps.

Compose Support: Yes inside activites.

Learn more


JVM Based solution, renders the screens without Device. It is as limited as Studio's Preview.

Compose Support: Yes.

Learn more

Inspired by Swift snapshot testing library

It is not specific for Screenshots, but serializable data. For our purpose it's mainly compose based, but extensible if required.

Compose Support: Yes.

Learn more


Writing your own

There are also critics of existing libraries, if you have been burned, you might want to write your own. Here is an article to get you started

Screenshots are also implemented in as somewhat custom way in this repository. Screenshots are taken when a test fail to see why it did. This can help identify failures like a System dialog showing so your Activity can't get focus.


License

License file

android-tutorial-test-showcase's People

Contributors

fknives avatar alexgabor avatar dependabot[bot] avatar zsoltboldizsar avatar

Stargazers

qiufeng avatar  avatar  avatar  avatar Blénesi Attila avatar  avatar

Watchers

 avatar

android-tutorial-test-showcase's Issues

Android Tests run slow

Describe the bug
Android tests run unnecessarily slow

To Reproduce
Steps to reproduce the behavior:
Running the tests will show that Espresso is waiting a lot, because an activity is not resumed.

Expected behavior
The tests shouldn't take so long to run

Smartphone (please complete the following information):

  • Device: doesn't matter
  • OS: doesn't matter

Additional context
Seems to be caused by the idling and synchronizations of AndroidTests. Since the Dispatcher is not swapped, when synchronizing with requests it seems to be stoping by waiting on the activities root.

Robolectric Tests fail on M1

Describe the bug
JVMTests fail on M1 chips, because of Robolectric version, update to min 4.7. reference: robolectric issues $6311

As Hilt was removed in issue#31, create a separate branch with only Hilt

Is your feature request related to a problem? Please describe.
Hilt is quite different from Koin, so an example would make sense to have.

Describe the solution you'd like
A separate branch with the same setup, just using Hilt instead of koin.

Additional context
Hilt was added previously before issue #31 so refer to those commits to reconstruct the hilt integration

Android Emulator Testing

Is your feature request related to a problem? Please describe.
We should integrate Android Emulator into GitHub Actions to run AndroidTests.

Describe the solution you'd like
A GitHub Action which runs AndroidTests.

Additional context
There are a couple of existing examples:
https://www.raywenderlich.com/10562143-continuous-integration-for-android#toc-anchor-010
https://linuxtut.com/en/5f12ed22d5b0aa4c4414/
https://github.com/google/android-emulator-container-scripts

Thanks for the suggestion and links @AlexGabor

Make MockServer setup more readable

Checking the code on github, there are a lot of "false" or dangling parameters, that are not obvious.
either used name parameters or make the API more readable

Confusing IndexOutOfBounds Crash when running tests on Emulator 21

Describe the bug
Tests are not run properly and a weird IndexOutOfBounds crash happens

Logs:

*** FATAL EXCEPTION IN SYSTEM PROCESS: main
E/AndroidRuntime( 1499): java.lang.ArrayIndexOutOfBoundsException: length=1; index=1
E/AndroidRuntime( 1499): 	at java.util.concurrent.CopyOnWriteArrayList.get(CopyOnWriteArrayList.java:117)
E/AndroidRuntime( 1499): 	at android.view.accessibility.AccessibilityManager.handleNotifyAccessibilityStateChanged(AccessibilityManager.java:645)
E/AndroidRuntime( 1499): 	at android.view.accessibility.AccessibilityManager.access$000(AccessibilityManager.java:68)
E/AndroidRuntime( 1499): 	at android.view.accessibility.AccessibilityManager$MyHandler.handleMessage(AccessibilityManager.java:693)
E/AndroidRuntime( 1499): 	at android.os.Handler.dispatchMessage(Handler.java:102)
E/AndroidRuntime( 1499): 	at android.os.Looper.loop(Looper.java:135)
E/AndroidRuntime( 1499): 	at com.android.server.SystemServer.run(SystemServer.java:269)
E/AndroidRuntime( 1499): 	at com.android.server.SystemServer.main(SystemServer.java:170)
E/AndroidRuntime( 1499): 	at java.lang.reflect.Method.invoke(Native Method)
E/AndroidRuntime( 1499): 	at java.lang.reflect.Method.invoke(Method.java:372)
E/AndroidRuntime( 1499): 	at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
E/AndroidRuntime( 1499): 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)
D/gralloc_ranchu( 1128): gralloc_alloc: Creating ashmem region of size 819200

Additional context
Add any other context about the problem here.
It looks like the whole AndroidTesting process crashed, since not all tests are listed

Emulator-Test-Results-21.zip

Emulator-Logcat-Logs-21.zip

Save Screenshot after failing UI Tests.

Is your feature request related to a problem? Please describe.
We have two flaky issue instances issue #99 and issue #97 .

Describe the solution you'd like
It would be nice if we also attached screenshots of the tests, to see exactly what happened on the device. Is it some kind of external factor or it is indeed the Test code that's at fault.

Example for Screenshot Testing

Is your feature request related to a problem? Please describe.
It would be great to have an example setup for Screenshot testing.

Describe the solution you'd like
Screenshot testing could easily help when migrating from Android View System to Compose. There is a library provided for it: https://github.com/pedrovgs/Shot which we could try out.

Implement integration Test for core and document it

Is your feature request related to a problem? Please describe.
Core only has unit tests, it could have integration tests as well.

Describe the solution you'd like
A new document with integration tests for Core, using the Networking fully.

Compose IdlingResources handling crash

Describe the bug
Flakiness of Compose tests are not fully fixed (original issue: #97)

Expected behavior
The Compose tests should not be flaky.

Additional context
The loopMainThreadFor inside awaitIdlingResources in AuthComposeInstrumentedTest has crashed with:

java.lang.RuntimeException: java.util.concurrent.ExecutionException: java.lang.IllegalStateException: Resource Compose-Espresso link isIdleNow() is returning true, but a message indicating that the resource has transitioned from busy to idle was never sent.

Meaning the Okhttp Idling resource didn't call callback, but stated that it became Idle. So that needs to be fixed.

Additional logs:

Emulator30-logs.zip

Invalid instruction in SharedTest: Wrong order of koin loading and database initialization

Describe the bug
In Section Login UI Test under subsection Application class

The instruction given puts database initialization before Koin initialization!

Expected behavior
The Instruction given is:

...
TestDatabaseInitialization.overwriteDatabaseInitialization(dispatcher)
if (GlobalContext.getOrNull() == null) {
    val application = ApplicationProvider.getApplicationContext<TestShowcaseApplication>()
    val baseUrl = BaseUrl(BuildConfig.BASE_URL)
    startKoin {
        androidContext(application)
        modules(createAppModules(baseUrl))
    }
}
...

Which should be:

...
Intents.init()
if (GlobalContext.getOrNull() == null) {
    val application = ApplicationProvider.getApplicationContext<TestShowcaseApplication>()
    val baseUrl = BaseUrl(BuildConfig.BASE_URL)
    startKoin {
        androidContext(application)
        modules(createAppModules(baseUrl))
    }
}
val dispatcher = StandardTestDispatcher()
...

So the order of initializing of koin and the database is in proper order.

Flacky Compose screen test

Describe the bug
AuthComposeActivity Test sometimes fails.

Expected behavior
The test should always behave the same way

Additional context
Failed on Emulator 30
Logs from CI:

org.fnives.test.showcase.ui.AuthComposeInstrumentedTest > networkErrorShowsProperErrorMessage[test(AVD) - 11] FAILED 
	androidx.compose.ui.test.ComposeTimeoutException: Condition still not satisfied after 1000 ms
	at androidx.compose.ui.test.junit4.AbstractMainTestClock$advanceTimeUntil$1.invoke(AbstractMainTestClock.kt:58)
org.fnives.test.showcase.ui.login.codekata.CodeKataAuthActivitySharedTest > null[test(AVD) - 11] SKIPPED 
Tests on test(AVD) - 11 failed: There was 1 failure(s).
Jul 12, 2022 7:26:56 AM com.google.testing.platform.RunnerImpl$Companion summarizeAndLogTestResult
SEVERE: Execute org.fnives.test.showcase.ui.AuthComposeInstrumentedTest.networkErrorShowsProperErrorMessage: FAILED
androidx.compose.ui.test.ComposeTimeoutException: androidx.compose.ui.test.ComposeTimeoutException: Condition still not satisfied after 1000 ms
at androidx.compose.ui.test.junit4.AbstractMainTestClock$advanceTimeUntil$1.invoke(AbstractMainTestClock.kt:58)
at androidx.compose.ui.test.junit4.AbstractMainTestClock$advanceTimeUntil$1.invoke(AbstractMainTestClock.kt:54)
at androidx.compose.ui.test.junit4.AndroidSynchronization_androidKt.runOnUiThread$lambda-0(AndroidSynchronization.android.kt:37)
at androidx.compose.ui.test.junit4.AndroidSynchronization_androidKt.$r8$lambda$JHfZTn-RG8lrYeP9BZG_AgROyug(Unknown Source:0)
at androidx.compose.ui.test.junit4.AndroidSynchronization_androidKt$$ExternalSyntheticLambda0.call(Unknown Source:2)
at java.util.concurrent.FutureTask.run(FutureTask.java:[266](https://github.com/fknives/AndroidTest-ShowCase/runs/7296766659?check_suite_focus=true#step:7:270))
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:462)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at android.app.Instrumentation$SyncRunnable.run(Instrumentation.java:2223)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7656)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
androidx.compose.ui.test.ComposeTimeoutException: Condition still not satisfied after 1000 ms
at androidx.compose.ui.test.junit4.AbstractMainTestClock$advanceTimeUntil$1.invoke(AbstractMainTestClock.kt:58)
at androidx.compose.ui.test.junit4.AbstractMainTestClock$advanceTimeUntil$1.invoke(AbstractMainTestClock.kt:54)
at androidx.compose.ui.test.junit4.AndroidSynchronization_androidKt.runOnUiThread$lambda-0(AndroidSynchronization.android.kt:37)
at androidx.compose.ui.test.junit4.AndroidSynchronization_androidKt.$r8$lambda$JHfZTn-RG8lrYeP9BZG_AgROyug(Unknown Source:0)
at androidx.compose.ui.test.junit4.AndroidSynchronization_androidKt$$ExternalSyntheticLambda0.call(Unknown Source:2)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:462)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at android.app.Instrumentation$SyncRunnable.run(Instrumentation.java:2223)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7656)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
Test results saved as file:/Users/runner/work/AndroidTest-ShowCase/AndroidTest-ShowCase/app/build/outputs/androidTest-results/connected/test(AVD)%20-%2011/test-result.pb. Inspect these results in Android Studio by selecting Run > Import Tests From File from the menu bar and importing test-result.pb.
> Task :app:connectedDebugAndroidTest FAILED
FAILURE: Build failed with an exception.

Remove Logged in State setup

This uses white box testing about the internals of the application.
Instead what could be done is ordering tests.
Login then do things on main activity.

However that might somewhat blow the testing in isolation. If it does, keep both examples.

Separate Koin and Hilt into completely different branches

The modules themselves look more complicated than they should be because both hilt and koin is used.

This is especially bad in the app module.

It was supposed to be like this so the maintainability is easier and one branch doesn't lag behind the other one, however the point of this repo is introduction and sample for tests. So Readability should be more important than the extra work with Maintaining the repository brings via separate branches.

Code Coverage metric

Is your feature request related to a problem? Please describe.
Code Coverage metric is not shown in the project. It would be great to describe how to do and see, if any tests are missed.

Describe the solution you'd like
A Code Coverage metric on the readme of the project and a task / description how it's achieved.

Espresso Test Recorder cannot be started on Compose Project

Describe the bug
Since the Project now contains Compose elements, the Espresso Test Recorder won't start.

To Reproduce
Select the Espresso Test Recorder.
=> Error is shown.

Expected behavior
We should be able to try out the Espresso Test Recorder.

As a compromise the SharedTest. instruction set should be modified, so it points the user to checkout 694d1bf before continuing.

Seaprate Utility Classes into separate reusable module

Is your feature request related to a problem? Please describe.
There are a couple of utility classes which could be useful for tests, make it easier to reuse, include on projects.

Describe the solution you'd like
Either a module, package and simple files that can be copy pasted or simply pulled into the project via gradle.

Describe alternatives you've considered
Copying the current utility classes with cross dependencies is possible but a bit of a headache.

SharedTests, MockNetworkRule not used

Describe the bug
In SharedTests, when discussing about the Rules, the MockNetworkRule is not added, like it is in the AuthActivityInstrumentedTest so the Database Initialization is again happens before the Koin reset.

Expected behavior
Before discussing the Applying rules, it should be mentioned to replace the Koin&Network mocking with a Rule.

Then in Applying describe that in the RuleChain.

Run Screenshot Rule on every API level

Is your feature request related to a problem? Please describe.
Screenshot Rule seems to be working differently on different API versions. It would be best to verify it works across all emulators.

Describe the solution you'd like
I would like a manual pipeline which can verify on all API levels that the Screenshot Rule with the image pulling works correctly.

OkHttp3IdlingResource fails to transition to idle state when there are multiple okhttp clients.

Describe the bug
There are two okhttp clients in the app (with session and without session).
It looks like the clients are sharing dispatchers which means that when OkHttp3IdlingResource sets the idleCallback on the second client's dispatcher it actually overrides the previous idle callback. This causes the first callback to never be called and Espresso detects this inconsistency and throws:

java.lang.IllegalStateException: Resource okhttp3.OkHttpClient@3595cf2 isIdleNow() is returning true, but a message indicating that the resource has transitioned from busy to idle was never sent.

The same problem reported on okhttp-idling-resource: JakeWharton/okhttp-idling-resource#10 (comment)

To Reproduce
Steps to reproduce the behavior:

  1. Checkout this commit acc45b7
  2. Run AuthComposeInstrumentedTest

Expected behavior

  1. The test should pass
  2. The clients should transition to idle if they are idle

Screenshots
Proof dispatcher is shared between two clients:
image

Smartphone (please complete the following information):
Emulator Nexus 5 API 31 (x86_64)

Additional context
Add any other context about the problem here.

Grammatical issues

I tried to gather the things I have noticed and consider that they are incorrect. I am no linguist so maybe I missed some things or corrected things incorrectly.

1. Starting of testing

  • @DisplayName("GIVEN error resposne response WHEN trying to login THEN session is not touched and error is returned")
  • The content data come comes from a RemoteSource class.
  • As usual we are staring starting with the easiest test.
  • We setup set up the request to succeed and expect a Loading and Success state to be returned.
  • I think the best place to start from is our most complicated test whenFetchingRequestIsCalledAgain since this is the one most likely to add additional unexpected values.
  • Note: if it confuses you why we need the additional advanceUntilIdle refer to the execution order descried described above.

2. Starting of networking testing

  • Let's setup set up our testClass:
  • First we setup set up our mockwebserver to return 400.
  • The basic idea with this is that it contains all the response, request jsons and make it easier to setup set up specific scenarios.

3. Starting of ViewModel testing

  • Next up we want to setup set up our TestObserver for LiveData. This enables us to verify the values sent into a LiveData.
  • However for completness completeness sake:
  • We just setup set up the UseCase:

4. Start of Integration tests

  • This These two tests would be really similar, so let's do Parametrized tests
  • There is no point of going over other integration test's tests in the core module, since the idea is captured, and nothing new could be shown.

5. Roboelectric Testing

  • So we are finally here, so far we didn't had have to touch any kind of context or resources, activities, fragments or anything Android.
  • That might not look the cleanest, so the presented way of switch switching out the koin-module creating the database is preferred.
  • We get the observable and it's its first element.
  • However for completness completeness sake:
  • This is handy, since our Network component, (OkHttp) uses it's own thread pool, and we would like to have a way to await the responses.

6. Shared tests

  • Our tests classess classes will be really similar to Robolectric since we are using the same components
  • First let’s setup set up our phone.
  • That’s becacuse because sharedTest package is added to the test sources.
  • So that’s bring that brings us to the first difference:
  • Since we are in the InstrumentedTest’s thread, all our coroutines will run there as well, which don’t doesn’t play well with LiveData. One idea would be to use LiveData ArchTaskExecutor.getInstance() and ensure our LiveData don’t doesn’t care about the Thread they are set from, But but then we would touch our Views from Non-Main Thread, which is still an issue.
  • So our test crashes in the tearDown, because the mockServerScenarioSetup is not initalized initialized?
  • This is great if you want to have End-to-End tests that follow each other, but since now we only want to tests some small subsection of the functionality, we have to restart Koin before every tests if it isn’t yet started so our tests don’t use the same instances.
  • This happens because animations can add continous continuous work to the MainThread thus never letting it become idle. The solution for this, to replace your Progress Bar or other infinetly infinitely animating element, with a simple view.
  • Pretty simple, we simple simply wrap the given Statement into our own, and in evaluation first we init the Intents and at the end we make sure it’s released.
  • Usually it’s better to use one of them which matches describes your need needs, that’s because it might take care of additional things you wouldn’t expect otherwise.
  • We create the modifyable modifiable private field and make it accessable accessible publicly to our tests.
  • The Rule chain starts our intentRule first, then the mainDispatcherRule, when cleaning up, first mainDispatcherRule will clean up then intentRule.
  • the generated tests, might still have issues in them, like syncronization synchronisation with Okhttp and such.
  • Since currently only Koin is available in this repo, for updates follow this issue, I thought to mentionen mentioned some issues with Hilt you may face:
  • An other Another issue can be that Crashlytics or similar services is are enabled in your tests.
  • When you get an simple bug ticket, write a test first which will fail if the bug is still present, then fix the bug.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.