A Kotlin Application that uses Dublin bus API to show when the next available bus will arrive. It uses Retrofit and MockWebServer to mock apis.
Go to the app module build.gradle and add the following dependencies
implementation 'com.github.bumptech.glide:glide:4.9.0'
implementation 'androidx.cardview:cardview:1.0.0'
implementation 'com.squareup.retrofit2:retrofit:2.8.1'
implementation 'com.squareup.retrofit2:converter-gson:2.8.1'
implementation 'com.squareup.retrofit2:converter-moshi:2.4.0'
implementation "androidx.recyclerview:recyclerview:1.1.0"
implementation "com.squareup.okhttp3:okhttp:4.4.0"
androidTestImplementation "com.squareup.okhttp3:mockwebserver:4.4.0"
androidTestImplementation 'com.jakewharton.espresso:okhttp3-idling-resource:1.0.0'
androidTestImplementation 'androidx.test:rules:1.2.0'
androidTestImplementation 'androidx.test:runner:1.2.0'
debugImplementation 'com.facebook.flipper:flipper:0.50.0'
debugImplementation 'com.facebook.soloader:soloader:0.9.0'
releaseImplementation 'com.facebook.flipper:flipper-noop:0.50.0'
repositories {
jcenter()
}
Go to the AndroidManifest.xml
and allow internet permission
<uses-permission android:name="android.permission.INTERNET"/>
In the AndroidManifest.xml
, make sure you add the name of the application you will use, in this instance it is BusApp
.
android:name="BusApp"
In the AndroidManifest.xml
, make sure you add the following or you may have issues using the MockTestRunner.
android:usesCleartextTraffic="true"
To store out json files like success_response.json
we want it stored in the following directory path app/src/debug/assets/success_response.json
. See the below image on how to create that debug directory
In the styles.xml
, make sure you change the style's parent if you don't want to show the action bar
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
The api we are fetching is not a normal list, it is an object that contains an array results
, in the array results
has the list of data we want. See how this api is different from other apis.
{
"errorcode": "0",
"errormessage": "",
"numberofresults": 3,
"stopid": "184",
"timestamp": "08/07/2020 23:29:20",
"results": [
{
"arrivaldatetime": "08/07/2020 23:31:42",
"duetime": "2222",
"departuredatetime": "08/07/2020 23:31:42",
"departureduetime": "2",
"scheduledarrivaldatetime": "08/07/2020 23:33:00",
"scheduleddeparturedatetime": "08/07/2020 23:33:00",
"destination": "O'Connell St",
"destinationlocalized": "Sr. Uí Chonaill",
"origin": "Harristown",
"originlocalized": "Baile Anraí",
"direction": "Outbound",
"operator": "bac",
"operatortype": "1",
"additionalinformation": "",
"lowfloorstatus": "no",
"route": "4",
"sourcetimestamp": "08/07/2020 23:24:15",
"monitored": "true"
},
In the AndroidManifest.xml
, make sure you add the following for Flipper debugger
<activity android:name="com.facebook.flipper.android.diagnostics.FlipperDiagnosticActivity"
android:exported="true"/>
In the BusApp.kt
, which is our application class, make sure you add the following for Flipper debugger
override fun onCreate() {
super.onCreate()
SoLoader.init(this, false)
if (BuildConfig.DEBUG && FlipperUtils.shouldEnableFlipper(
this
)
) {
val client = AndroidFlipperClient.getInstance(this)
client.addPlugin(InspectorFlipperPlugin(this, DescriptorMapping.withDefaults()))
client.start()
}
}
To use Proxyman on an Android Emulator, look at the following documentation link.
Firstly, add the following to AndroidManifest.xml
android:networkSecurityConfig="@xml/network_security_config"
Then create the following file res/xml/network_security_config.xml
and add the following
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<!--Set application-wide security config using base-config tag.-->
<!--Set domain-specific security config using domain-config tags. -->
<!--See https://developer.android.com/training/articles/security-config.html for more information.-->
<debug-overrides>
<trust-anchors>
<!-- Trust user added CAs while debuggable only -->
<certificates src="system" />
<certificates src="user" />
</trust-anchors>
</debug-overrides>
<base-config cleartextTrafficPermitted="true">
<trust-anchors>
<certificates src="system" />
</trust-anchors>
</base-config>
<domain-config>
<domain includeSubdomains="true">www.google.com</domain>
<trust-anchors>
<certificates src="user"/>
<certificates src="system"/>
</trust-anchors>
</domain-config>
</network-security-config>
Look at the documentation mentioned above on how to setup a Proxyman on a Pixel 3 emulator.
Important to note if running test directly via localhost:
If for example we wanted to create a new Phone and Tablet module
that copied another module that had a live url and in this module we just used the localhost
instead of a live url, we wouldn't then need BusTestApp.kt
and MockTestRunner.kt
and we would need to update the FileReader.kt
to be the following
import androidx.test.platform.app.InstrumentationRegistry
import java.io.IOException
import java.io.InputStreamReader
object FileReader {
fun readStringFromFile(fileName: String): String {
try {
val inputStream = InstrumentationRegistry.getInstrumentation().targetContext
.applicationContext.assets.open(fileName)
val builder = StringBuilder()
val reader = InputStreamReader(inputStream, "UTF-8")
reader.readLines().forEach {
builder.append(it)
}
return builder.toString()
} catch (e: IOException) {
throw e
}
}
}
To run the unit tests locally.
./gradlew testdebugUnitTest
To run the ui tests locally, but first we need an emulator to be open.
./gradlew connectedCheck
To create app-debug.apk
with fastlane locally, run the following.
bundle exec fastlane beta
To upldoad app-debug.apk
to App Center with fastlane locally, run the following.
bundle exec fastlane upload_to_app_center
Linter: we use the following linter link.
Uploading Artifacts: we use the following way to upload Artifacts, they allow you to persist data like test results after a job has completed, see the following documentation link.
Creating a Mock Server: we use a mock server with Postman to quickly test apis, to see how to create a mock server, see the following video link.
Fastlane: Fastlane allows us to automate our development and release process link.
App Center: App Center is used to distribute an app, making it very easy to test on a physical device by using a fastlane plugin link.
Npm: How to update a npm package.
- link.
Gemfile: How to update a Gemfile package.
- link.
How to manage releases in a repository link.
The following link provides very helpful information on Retrofit and mocking using MockWebServer.
- link.
The following link goes into leveling up your ui tests with MockWebServer
- link.
The following link provides a guide on consuming apis with Retrofit
- link.
The following link helps if you get the following error Failed to open QEMU pipe 'qemud:network': Invalid argument
.
- link.
The following link provides information if you failed to define the application in the manifest.
- link.
The following link provides information on how to use the image dependency Glide, which is good for gifs.
- link.
The following link provides information on how to use the debugging tool Flipper for Android.
- link.
The following link provides information on how to convert from using Gson to Moshi.
- link.
The following link provides Moshi's official github which provides examples on how to use Moshi.
- link.
The following link provides info on setting up code coverage with the JaCoCo plugin.
- link.
The following link provides info on Unresolved reference: kotlinx.
- link.
The following link provides info on how to setup Proxyman on Android.
- link.
The following link provides info on how to setup a corresponding link url in the Github Actions interface.
- link.