- Tests passed

- Weather API successfully replaces
This commit is contained in:
2024-10-02 00:17:29 +01:00
parent 6e28db5feb
commit 406402111b
35 changed files with 43142 additions and 11729 deletions

View File

@@ -18,8 +18,8 @@ android {
applicationId "com.appttude.h_mal.atlas_weather"
minSdkVersion MIN_SDK_VERSION
targetSdkVersion TARGET_SDK_VERSION
versionCode 5
versionName "3.0"
versionCode 6
versionName "3.1"
testInstrumentationRunner "com.appttude.h_mal.atlas_weather.application.TestRunner"
vectorDrawables.useSupportLibrary = true
@@ -32,6 +32,10 @@ android {
buildConfigField "String", "ParamOne", System.getenv('WEATHER_API')
buildConfigField "String", "ParamTwo", System.getenv('SEARCH_API')
}
packagingOptions {
resources.excludes.add("META-INF/*")
}
}
android {
sourceSets {

View File

@@ -1,4 +0,0 @@
{
"cod": 401,
"message": "Invalid API key. Please see http://openweathermap.org/faq#error401 for more info."
}

View File

@@ -0,0 +1 @@
No account found with API key 'wrong api key'

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -67,7 +67,7 @@ open class BaseTest<A : Activity>(
}
testApp =
InstrumentationRegistry.getInstrumentation().targetContext.applicationContext
InstrumentationRegistry.getInstrumentation().targetContext.applicationContext as TestAppClass
runBlocking {
beforeLaunch()
}
@@ -80,8 +80,8 @@ open class BaseTest<A : Activity>(
afterLaunch()
}
fun stubEndpoint(url: String, stub: Stubs, code: Int = 200) {
testApp.stubUrl(url, stub.id, code)
fun stubEndpoint(url: String, stub: Stubs, code: Int = 200, extension: String = ".json") {
testApp.stubUrl(url, stub.id, code, extension)
}
fun unstubEndpoint(url: String) {
@@ -125,7 +125,6 @@ open class BaseTest<A : Activity>(
})
}
@Suppress("DEPRECATION")
fun checkToastMessage(message: String) {
Espresso.onView(ViewMatchers.withText(message)).inRoot(withDecorView(Matchers.not(decorView)))
.check(ViewAssertions.matches(ViewMatchers.isDisplayed()))

View File

@@ -17,7 +17,12 @@ import androidx.test.espresso.action.ViewActions.swipeDown
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.contrib.PickerActions
import androidx.test.espresso.contrib.RecyclerViewActions
import androidx.test.espresso.matcher.ViewMatchers.*
import androidx.test.espresso.matcher.ViewMatchers.hasDescendant
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
import androidx.test.espresso.matcher.ViewMatchers.isRoot
import androidx.test.espresso.matcher.ViewMatchers.withClassName
import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.espresso.matcher.ViewMatchers.withText
import com.appttude.h_mal.atlas_weather.helpers.EspressoHelper.waitForView
import com.appttude.h_mal.atlas_weather.helpers.checkErrorMessage
import com.appttude.h_mal.atlas_weather.helpers.checkImage

View File

@@ -16,9 +16,9 @@ class MockingNetworkInterceptor(
override fun intercept(chain: Interceptor.Chain): Response {
idlingResource.increment()
val original = chain.request()
val originalHttpUrl = original.url.toString().split("?")[0]
val originalHttpUrl = original.url.toString()
feedMap[originalHttpUrl]?.let { responsePair ->
feedMap[feedMap.keys.first { originalHttpUrl.contains(it) }]?.let { responsePair ->
val code = responsePair.second
val jsonBody = responsePair.first

View File

@@ -9,5 +9,4 @@ enum class Stubs(
WrongLocation("wrong_location_response"),
InvalidKey("invalid_api_key_response"),
Sydney("valid_response_metric_sydney"),
New("new_response")
}

View File

@@ -7,7 +7,7 @@ import androidx.test.platform.app.InstrumentationRegistry
import com.appttude.h_mal.atlas_weather.data.location.LocationProvider
import com.appttude.h_mal.atlas_weather.data.location.MockLocationProvider
import com.appttude.h_mal.atlas_weather.data.network.NetworkModule
import com.appttude.h_mal.atlas_weather.data.network.NewWeatherApi
import com.appttude.h_mal.atlas_weather.data.network.WeatherApi
import com.appttude.h_mal.atlas_weather.data.network.interceptors.MockingNetworkInterceptor
import com.appttude.h_mal.atlas_weather.data.network.interceptors.NetworkConnectionInterceptor
import com.appttude.h_mal.atlas_weather.data.network.interceptors.QueryParamsInterceptor
@@ -28,8 +28,8 @@ class TestAppClass : AppClass() {
IdlingRegistry.getInstance().register(idlingResources)
}
override fun createNetworkModule(): NewWeatherApi {
return NetworkModule().invoke<NewWeatherApi>(
override fun createNetworkModule(): WeatherApi {
return NetworkModule().invoke<WeatherApi>(
mockingNetworkInterceptor,
NetworkConnectionInterceptor(this),
QueryParamsInterceptor(),
@@ -49,9 +49,9 @@ class TestAppClass : AppClass() {
return database
}
fun stubUrl(url: String, rawPath: String, code: Int = 200) {
fun stubUrl(url: String, rawPath: String, code: Int = 200, extension: String = ".json") {
val iStream =
InstrumentationRegistry.getInstrumentation().context.assets.open("$rawPath.json")
InstrumentationRegistry.getInstrumentation().context.assets.open("$rawPath$extension")
val data = iStream.bufferedReader().use(BufferedReader::readText)
mockingNetworkInterceptor.addUrlStub(url = url, data = data, code = code)
}

View File

@@ -13,6 +13,7 @@ import com.appttude.h_mal.atlas_weather.BaseTestRobot
import com.appttude.h_mal.atlas_weather.R
import com.appttude.h_mal.atlas_weather.helpers.EspressoHelper.waitForView
import com.appttude.h_mal.atlas_weather.model.types.UnitType
import com.appttude.h_mal.atlas_weather.model.types.UnitType.Companion.getLabel
fun settingsScreen(func: SettingsScreen.() -> Unit) = SettingsScreen().apply { func() }

View File

@@ -9,6 +9,7 @@ import com.appttude.h_mal.atlas_weather.utils.Stubs
import com.appttude.h_mal.atlas_weather.robot.furtherInfoScreen
import com.appttude.h_mal.atlas_weather.robot.settingsScreen
import com.appttude.h_mal.atlas_weather.robot.weatherScreen
import com.appttude.h_mal.atlas_weather.utils.baseUrl
import org.junit.Test
import tools.fastlane.screengrab.Screengrab
@@ -17,7 +18,7 @@ import tools.fastlane.screengrab.Screengrab
class SnapshotCaptureTest : BaseTest<MainActivity>(MainActivity::class.java) {
override fun beforeLaunch() {
stubEndpoint("https://api.openweathermap.org/data/2.5/onecall", Stubs.Metric)
stubEndpoint(baseUrl, Stubs.Metric)
stubLocation("London", 51.51, -0.13)
clearPrefs()
}
@@ -50,7 +51,7 @@ class SnapshotCaptureTest : BaseTest<MainActivity>(MainActivity::class.java) {
openMenuItem()
}
settingsScreen {
stubEndpoint("https://api.openweathermap.org/data/2.5/onecall", Stubs.Imperial)
stubEndpoint(baseUrl, Stubs.Imperial)
Screengrab.screenshot("SettingsScreen")
}
}

View File

@@ -1,36 +1,27 @@
package com.appttude.h_mal.atlas_weather.tests
import com.appttude.h_mal.atlas_weather.BaseTest
import com.appttude.h_mal.atlas_weather.robot.homeScreen
import com.appttude.h_mal.atlas_weather.ui.MainActivity
import com.appttude.h_mal.atlas_weather.utils.Stubs
import com.appttude.h_mal.atlas_weather.robot.homeScreen
import com.appttude.h_mal.atlas_weather.utils.baseUrl
import org.junit.Test
class HomePageNoDataUITest : BaseTest<MainActivity>(MainActivity::class.java) {
override fun beforeLaunch() {
stubEndpoint("https://api.openweathermap.org/data/2.5/onecall", Stubs.InvalidKey, 400)
}
@Test
fun loadApp_invalidKeyWeatherResponse_returnsEmptyViewPage() {
homeScreen {
waitFor(2000)
// verify empty
verifyUnableToRetrieve()
}
stubEndpoint(baseUrl, Stubs.InvalidKey, 400, ".txt")
}
@Test
fun invalidKeyWeatherResponse_swipeToRefresh_returnsValidPage() {
homeScreen {
waitFor(2000)
// verify empty
verifyUnableToRetrieve()
stubEndpoint("https://api.openweathermap.org/data/2.5/onecall", Stubs.Metric)
stubEndpoint(baseUrl, Stubs.Metric)
refresh()
verifyCurrentTemperature(2)
verifyCurrentTemperature(13)
verifyCurrentLocation("Mock Location")
}
}

View File

@@ -5,19 +5,20 @@ import com.appttude.h_mal.atlas_weather.BaseTest
import com.appttude.h_mal.atlas_weather.robot.homeScreen
import com.appttude.h_mal.atlas_weather.ui.MainActivity
import com.appttude.h_mal.atlas_weather.utils.Stubs
import com.appttude.h_mal.atlas_weather.utils.baseUrl
import org.junit.Test
class HomePageUITest : BaseTest<MainActivity>(MainActivity::class.java) {
override fun beforeLaunch() {
stubEndpoint("https://api.openweathermap.org/data/2.5/onecall", Stubs.Metric)
stubEndpoint(baseUrl, Stubs.Metric)
}
@Test
fun loadApp_validWeatherResponse_returnsValidPage() {
homeScreen {
isDisplayed()
verifyCurrentTemperature(2)
verifyCurrentTemperature(13)
verifyCurrentLocation("Mock Location")
}
}

View File

@@ -7,7 +7,7 @@ import androidx.test.platform.app.InstrumentationRegistry
import com.appttude.h_mal.atlas_weather.data.location.LocationProvider
import com.appttude.h_mal.atlas_weather.data.location.MockLocationProvider
import com.appttude.h_mal.atlas_weather.data.network.NetworkModule
import com.appttude.h_mal.atlas_weather.data.network.NewWeatherApi
import com.appttude.h_mal.atlas_weather.data.network.WeatherApi
import com.appttude.h_mal.atlas_weather.data.network.interceptors.MockingNetworkInterceptor
import com.appttude.h_mal.atlas_weather.data.network.interceptors.NetworkConnectionInterceptor
import com.appttude.h_mal.atlas_weather.data.network.interceptors.QueryParamsInterceptor
@@ -18,7 +18,6 @@ import org.kodein.di.LazyKodein
import java.io.BufferedReader
class TestAppClass : AppClass() {
override val kodein: LazyKodein = super.kodein
private val idlingResources = CountingIdlingResource("Data_loader")
@@ -32,13 +31,13 @@ class TestAppClass : AppClass() {
IdlingRegistry.getInstance().register(idlingResources)
}
override fun createNetworkModule(): NewWeatherApi {
return NetworkModule().invoke<NewWeatherApi>(
override fun createNetworkModule(): WeatherApi {
return NetworkModule().invoke<WeatherApi>(
mockingNetworkInterceptor,
NetworkConnectionInterceptor(this),
QueryParamsInterceptor(),
loggingInterceptor
) as NewWeatherApi
) as WeatherApi
}
override fun createLocationModule(): LocationProvider {
@@ -53,9 +52,9 @@ class TestAppClass : AppClass() {
return database
}
fun stubUrl(url: String, rawPath: String, code: Int = 200) {
fun stubUrl(url: String, rawPath: String, code: Int = 200, extension: String = ".json") {
val iStream =
InstrumentationRegistry.getInstrumentation().context.assets.open("$rawPath.json")
InstrumentationRegistry.getInstrumentation().context.assets.open("$rawPath$extension")
val data = iStream.bufferedReader().use(BufferedReader::readText)
mockingNetworkInterceptor.addUrlStub(url = url, data = data, code = code)
}

View File

@@ -10,7 +10,6 @@ import com.appttude.h_mal.atlas_weather.utils.baseUrl
import com.appttude.h_mal.monoWeather.robot.furtherInfoScreen
import com.appttude.h_mal.monoWeather.robot.settingsScreen
import com.appttude.h_mal.monoWeather.robot.weatherScreen
import org.junit.Ignore
import org.junit.Test
import tools.fastlane.screengrab.Screengrab
@@ -19,7 +18,7 @@ import tools.fastlane.screengrab.Screengrab
class SnapshotCaptureTest : BaseTest<MainActivity>(MainActivity::class.java) {
override fun beforeLaunch() {
stubEndpoint(baseUrl, Stubs.New)
stubEndpoint(baseUrl, Stubs.Metric)
stubLocation("London", 51.5064, -0.12721)
clearPrefs()
}
@@ -53,7 +52,7 @@ class SnapshotCaptureTest : BaseTest<MainActivity>(MainActivity::class.java) {
openMenuItem()
}
settingsScreen {
stubEndpoint("https://api.openweathermap.org/data/2.5/onecall", Stubs.Imperial)
stubEndpoint(baseUrl, Stubs.Imperial)
Screengrab.screenshot("SettingsScreen")
}
}

View File

@@ -3,7 +3,6 @@ package com.appttude.h_mal.monoWeather.robot
import com.appttude.h_mal.atlas_weather.BaseTestRobot
import com.appttude.h_mal.atlas_weather.R
import com.appttude.h_mal.monoWeather.ui.home.adapter.forecastDaily.ViewHolderForecastDaily
import com.appttude.h_mal.monoWeather.ui.home.adapter.further.ViewHolderFurtherDetails
fun weatherScreen(func: WeatherScreen.() -> Unit) = WeatherScreen().apply { func() }
class WeatherScreen : BaseTestRobot() {

View File

@@ -4,36 +4,30 @@ package com.appttude.h_mal.monoWeather.tests
import com.appttude.h_mal.atlas_weather.BaseTest
import com.appttude.h_mal.atlas_weather.ui.MainActivity
import com.appttude.h_mal.atlas_weather.utils.Stubs
import com.appttude.h_mal.atlas_weather.utils.baseUrl
import com.appttude.h_mal.monoWeather.robot.weatherScreen
import org.junit.Ignore
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runners.MethodSorters
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class HomePageNoDataUITest : BaseTest<MainActivity>(MainActivity::class.java) {
override fun beforeLaunch() {
// Todo: change this
stubEndpoint("https://api.openweathermap.org/data/2.5/onecall", Stubs.InvalidKey, 400)
stubEndpoint(baseUrl, Stubs.InvalidKey, 400, ".txt")
}
@Test
fun loadApp_invalidKeyWeatherResponse_returnsEmptyViewPage() {
weatherScreen {
// verify empty
verifyUnableToRetrieve()
}
}
@Ignore("Test is flakey - must investigate")
@Test
fun invalidKeyWeatherResponse_swipeToRefresh_returnsValidPage() {
weatherScreen {
// verify empty
verifyUnableToRetrieve()
stubEndpoint("https://api.openweathermap.org/data/2.5/onecall", Stubs.Metric)
stubEndpoint(baseUrl, Stubs.Metric)
refresh()
verifyCurrentTemperature(2)
verifyCurrentTemperature(13)
verifyCurrentLocation("Mock Location")
}
}
}

View File

@@ -2,19 +2,17 @@ package com.appttude.h_mal.monoWeather.tests
import com.appttude.h_mal.atlas_weather.BaseTest
import com.appttude.h_mal.atlas_weather.model.types.UnitType
import com.appttude.h_mal.atlas_weather.ui.MainActivity
import com.appttude.h_mal.atlas_weather.utils.Stubs
import com.appttude.h_mal.atlas_weather.utils.baseUrl
import com.appttude.h_mal.monoWeather.robot.furtherInfoScreen
import com.appttude.h_mal.monoWeather.robot.settingsScreen
import com.appttude.h_mal.monoWeather.robot.weatherScreen
import org.junit.Test
class HomePageUITest : BaseTest<MainActivity>(MainActivity::class.java) {
override fun beforeLaunch() {
stubEndpoint(baseUrl, Stubs.New)
stubEndpoint(baseUrl, Stubs.Metric)
clearPrefs()
}
@@ -22,7 +20,7 @@ class HomePageUITest : BaseTest<MainActivity>(MainActivity::class.java) {
fun loadApp_validWeatherResponse_returnsValidPage() {
weatherScreen {
isDisplayed()
verifyCurrentTemperature(2)
verifyCurrentTemperature(13)
verifyCurrentLocation("Mock Location")
}
}
@@ -31,35 +29,15 @@ class HomePageUITest : BaseTest<MainActivity>(MainActivity::class.java) {
fun loadApp_validWeatherResponse_viewFurtherDetailsPage() {
weatherScreen {
isDisplayed()
verifyCurrentTemperature(2)
verifyCurrentTemperature(13)
verifyCurrentLocation("Mock Location")
tapDayInformationByPosition(4)
}
furtherInfoScreen {
isDisplayed()
verifyMaxTemperature(12)
verifyAverageTemperature(9)
verifyMaxTemperature(15)
verifyAverageTemperature(11)
}
}
@Test
fun loadApp_changeToImperial_returnsValidPage() {
weatherScreen {
isDisplayed()
verifyCurrentTemperature(2)
verifyCurrentLocation("Mock Location")
stubEndpoint("https://api.openweathermap.org/data/2.5/onecall", Stubs.Imperial)
openMenuItem()
}
settingsScreen {
selectWeatherUnits(UnitType.IMPERIAL)
goBack()
}
weatherScreen {
isDisplayed()
refresh()
verifyCurrentTemperature(58)
verifyCurrentLocation("Mock Location")
}
}
}

View File

@@ -0,0 +1,40 @@
package com.appttude.h_mal.monoWeather.tests
import com.appttude.h_mal.atlas_weather.BaseTest
import com.appttude.h_mal.atlas_weather.model.types.UnitType
import com.appttude.h_mal.atlas_weather.ui.MainActivity
import com.appttude.h_mal.atlas_weather.utils.Stubs
import com.appttude.h_mal.atlas_weather.utils.baseUrl
import com.appttude.h_mal.monoWeather.robot.settingsScreen
import com.appttude.h_mal.monoWeather.robot.weatherScreen
import org.junit.Test
class SettingsPageUITest : BaseTest<MainActivity>(MainActivity::class.java) {
override fun beforeLaunch() {
stubEndpoint(baseUrl, Stubs.Metric)
clearPrefs()
}
@Test
fun loadApp_changeToImperial_returnsValidPage() {
weatherScreen {
isDisplayed()
verifyCurrentTemperature(13)
verifyCurrentLocation("Mock Location")
stubEndpoint(baseUrl, Stubs.Imperial)
openMenuItem()
}
settingsScreen {
selectWeatherUnits(UnitType.IMPERIAL)
goBack()
}
weatherScreen {
isDisplayed()
refresh()
verifyCurrentTemperature(56)
verifyCurrentLocation("Mock Location")
}
}
}

View File

@@ -15,8 +15,8 @@ import org.junit.Test
class WorldPageUITest : BaseTest<MainActivity>(MainActivity::class.java) {
override fun beforeLaunch() {
stubEndpoint(baseUrl, Stubs.New)
stubLocation("London", 51.5064, -0.12721)
stubEndpoint(baseUrl, Stubs.Metric)
stubLocation("London", 51.5064,-0.12721)
}
@Test
@@ -28,9 +28,8 @@ class WorldPageUITest : BaseTest<MainActivity>(MainActivity::class.java) {
clickFab()
}
addLocation {
// Todo: change this
stubEndpoint("https://api.openweathermap.org/data/2.5/onecall", Stubs.Sydney)
stubLocation("Sydney", -33.89, -151.12)
stubEndpoint(baseUrl, Stubs.Sydney)
stubLocation("Sydney",-33.8696,151.207)
setLocation("Sydney")
submit()
}
@@ -39,7 +38,7 @@ class WorldPageUITest : BaseTest<MainActivity>(MainActivity::class.java) {
}
weatherScreen {
isDisplayed()
verifyCurrentTemperature(12)
verifyCurrentTemperature(16)
verifyCurrentLocation("Sydney")
}
}

View File

@@ -3,7 +3,7 @@ package com.appttude.h_mal.atlas_weather.application
import com.appttude.h_mal.atlas_weather.data.location.LocationProvider
import com.appttude.h_mal.atlas_weather.data.location.LocationProviderImpl
import com.appttude.h_mal.atlas_weather.data.network.NetworkModule
import com.appttude.h_mal.atlas_weather.data.network.NewWeatherApi
import com.appttude.h_mal.atlas_weather.data.network.WeatherApi
import com.appttude.h_mal.atlas_weather.data.network.interceptors.NetworkConnectionInterceptor
import com.appttude.h_mal.atlas_weather.data.network.interceptors.QueryParamsInterceptor
import com.appttude.h_mal.atlas_weather.data.network.networkUtils.loggingInterceptor
@@ -11,12 +11,12 @@ import com.appttude.h_mal.atlas_weather.data.room.AppDatabase
open class AppClass : BaseAppClass() {
override fun createNetworkModule(): NewWeatherApi {
return NetworkModule().invoke<NewWeatherApi>(
override fun createNetworkModule(): WeatherApi {
return NetworkModule().invoke<WeatherApi>(
NetworkConnectionInterceptor(this),
QueryParamsInterceptor(),
loggingInterceptor
) as NewWeatherApi
) as WeatherApi
}
override fun createLocationModule(): LocationProvider = LocationProviderImpl(this)

View File

@@ -4,6 +4,7 @@ import android.app.Application
import com.appttude.h_mal.atlas_weather.data.WeatherSource
import com.appttude.h_mal.atlas_weather.data.location.LocationProvider
import com.appttude.h_mal.atlas_weather.data.network.Api
import com.appttude.h_mal.atlas_weather.data.network.WeatherApi
import com.appttude.h_mal.atlas_weather.data.prefs.PreferenceProvider
import com.appttude.h_mal.atlas_weather.data.repository.RepositoryImpl
import com.appttude.h_mal.atlas_weather.data.repository.SettingsRepositoryImpl
@@ -28,7 +29,7 @@ abstract class BaseAppClass : Application(), KodeinAware {
val parentModule = Kodein.Module("Parent Module", allowSilentOverride = true) {
import(androidXModule(this@BaseAppClass))
bind() from singleton { createNetworkModule() }
bind() from singleton { createNetworkModule() as WeatherApi }
bind() from singleton { createLocationModule() }
bind() from singleton { Gson() }

View File

@@ -1,9 +1,7 @@
package com.appttude.h_mal.atlas_weather.data.network
import org.json.JSONException
import org.json.JSONObject
import retrofit2.HttpException
import retrofit2.Response
import java.io.IOException
abstract class ResponseUnwrap {
@@ -15,18 +13,7 @@ abstract class ResponseUnwrap {
if (response.isSuccessful) {
return response.body()!!
} else {
val error = response.errorBody()?.string()
val errorMessage = error?.let {
try {
JSONObject(it).getString("message")
} catch (e: JSONException) {
e.printStackTrace()
null
}
} ?: "Error Code: ${response.code()}"
throw IOException(errorMessage)
throw HttpException(response)
}
}
}

View File

@@ -7,13 +7,13 @@ import retrofit2.http.Path
import retrofit2.http.Query
interface NewWeatherApi : Api {
interface WeatherApi : Api {
@GET("{location}")
suspend fun getFromApi(
@Path("location") location: String,
@Query("contentType") exclude: String = "json",
@Query("unitGroup") units: String = "uk",
@Path("location") location: String
@Query("unitGroup") units: String = "metric"
): Response<WeatherApiResponse>
}

View File

@@ -0,0 +1,16 @@
package com.appttude.h_mal.atlas_weather.data.network.response.weather
import com.google.gson.annotations.SerializedName
data class Alerts(
@SerializedName("event") var event: String? = null,
@SerializedName("headline") var headline: String? = null,
@SerializedName("ends") var ends: String? = null,
@SerializedName("endsEpoch") var endsEpoch: Int? = null,
@SerializedName("onset") var onset: String? = null,
@SerializedName("onsetEpoch") var onsetEpoch: Int? = null,
@SerializedName("id") var id: String? = null,
@SerializedName("language") var language: String? = null,
@SerializedName("link") var link: String? = null,
@SerializedName("description") var description: String? = null,
)

View File

@@ -18,7 +18,7 @@ data class WeatherApiResponse(
@SerializedName("tzoffset") var tzoffset: Int? = null,
@SerializedName("description") var description: String? = null,
@SerializedName("days") var days: ArrayList<Days> = arrayListOf(),
@SerializedName("alerts") var alerts: ArrayList<String> = arrayListOf(),
@SerializedName("alerts") var alerts: ArrayList<Alerts> = arrayListOf(),
@SerializedName("currentConditions") var currentConditions: CurrentConditions? = CurrentConditions()
): DataMapper<FullWeather> {

View File

@@ -1,7 +1,7 @@
package com.appttude.h_mal.atlas_weather.data.repository
import com.appttude.h_mal.atlas_weather.data.network.NewWeatherApi
import com.appttude.h_mal.atlas_weather.data.network.ResponseUnwrap
import com.appttude.h_mal.atlas_weather.data.network.WeatherApi
import com.appttude.h_mal.atlas_weather.data.network.response.weather.WeatherApiResponse
import com.appttude.h_mal.atlas_weather.data.prefs.LOCATION_CONST
import com.appttude.h_mal.atlas_weather.data.prefs.PreferenceProvider
@@ -12,7 +12,7 @@ import com.appttude.h_mal.atlas_weather.utils.FALLBACK_TIME
class RepositoryImpl(
private val api: NewWeatherApi,
private val api: WeatherApi,
private val db: AppDatabase,
private val prefs: PreferenceProvider
) : Repository, ResponseUnwrap() {
@@ -21,7 +21,8 @@ class RepositoryImpl(
lat: String,
long: String
): WeatherApiResponse {
return responseUnwrap { api.getFromApi(location = lat + long) }
val unit = if (prefs.getUnitsType() == UnitType.METRIC) "metric" else "us"
return responseUnwrap { api.getFromApi(location = "$lat,$long", units = unit) }
}
override suspend fun saveCurrentWeatherToRoom(entityItem: EntityItem) {

View File

@@ -190,7 +190,7 @@ class ServicesHelper(
val list = mutableListOf<InnerWidgetCellData>()
result.weather.daily?.drop(1)?.dropLast(2)?.forEach { dailyWeather ->
result.weather.daily?.drop(1)?.dropLast(1)?.forEach { dailyWeather ->
val day = dailyWeather.dt?.toSmallDayName()
val icon = dailyWeather.icon
val temp = dailyWeather.max?.toInt().toString()
@@ -220,7 +220,7 @@ class ServicesHelper(
val list = mutableListOf<InnerWidgetCellData>()
result.weather.daily?.drop(1)?.dropLast(2)?.forEach { dailyWeather ->
result.weather.daily?.drop(1)?.dropLast(1)?.forEach { dailyWeather ->
val day = dailyWeather.dt?.toSmallDayName()
val icon = dailyWeather.icon
val temp = dailyWeather.max?.toInt().toString()

View File

@@ -1,6 +1,6 @@
package com.appttude.h_mal.atlas_weather.data.repository
import com.appttude.h_mal.atlas_weather.data.network.NewWeatherApi
import com.appttude.h_mal.atlas_weather.data.network.WeatherApi
import com.appttude.h_mal.atlas_weather.data.network.response.weather.WeatherApiResponse
import com.appttude.h_mal.atlas_weather.data.prefs.LOCATION_CONST
import com.appttude.h_mal.atlas_weather.data.prefs.PreferenceProvider
@@ -18,7 +18,8 @@ import kotlinx.coroutines.runBlocking
import org.junit.Before
import org.junit.Test
import org.mockito.ArgumentMatchers.anyDouble
import java.io.IOException
import org.mockito.ArgumentMatchers.anyString
import retrofit2.HttpException
import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
import kotlin.test.assertIs
@@ -30,7 +31,7 @@ class RepositoryImplTest : BaseTest() {
lateinit var repository: RepositoryImpl
@MockK lateinit var api: NewWeatherApi
@MockK lateinit var api: WeatherApi
@MockK
lateinit var db: AppDatabase
@@ -93,7 +94,7 @@ class RepositoryImplTest : BaseTest() {
//Act
//create a successful retrofit response
every { prefs.getUnitsType() } returns (UnitType.METRIC)
coEvery { api.getFromApi(location = lat + long) }.returns(mockResponse)
coEvery { api.getFromApi(location = "$lat,$long") }.returns(mockResponse)
// Assert
runBlocking {
@@ -105,20 +106,25 @@ class RepositoryImplTest : BaseTest() {
@Test
fun getWeatherFromApi_validLatLong_invalidResponse() {
//Arrange
val mockResponse = createErrorRetrofitMock<WeatherApiResponse>()
val errorMessage = "Why dont you have a valid api key?"
val mockResponse = createErrorRetrofitMock<WeatherApiResponse>(errorMessage)
val lat = anyString()
val long = anyString()
//Act
//create a successful retrofit response
every { prefs.getUnitsType() } returns (UnitType.METRIC)
coEvery { api.getFromApi(location = any()) } returns (mockResponse)
coEvery { api.getFromApi(location = "$lat,$long") } returns (mockResponse)
// Assert
val ioExceptionReturned = assertFailsWith<IOException> {
val ioExceptionReturned = assertFailsWith<HttpException> {
runBlocking {
repository.getWeatherFromApi("", "")
repository.getWeatherFromApi(lat, long)
}
}
assertEquals(ioExceptionReturned.message, "Error Code: 400")
assertEquals(ioExceptionReturned.code(), 400)
assertEquals(ioExceptionReturned.message(), "Why dont you have a valid api key?")
}
@Test

View File

@@ -4,7 +4,9 @@ import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import io.mockk.every
import io.mockk.mockk
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.ResponseBody
import okhttp3.ResponseBody.Companion.toResponseBody
import retrofit2.Response
@@ -29,9 +31,17 @@ open class BaseTest {
fun <T: Any> createErrorRetrofitMock(code: Int = 400): Response<T> {
val responseBody = mockk<ResponseBody>(relaxed = true)
val rawResponse = mockk<okhttp3.Response>().also {
every { it.code } returns code
}
return Response.error<T>(code, responseBody)
}
fun <T: Any> createErrorRetrofitMock(errorMessage: String, code: Int = 400): Response<T> {
val responseBody = errorMessage.toResponseBody("application/json".toMediaType())
val rawResponse = mockk<okhttp3.Response>(relaxed = true).also {
every { it.code } returns code
every { it.isSuccessful } returns false
every { it.body } returns responseBody
every { it.message } returns errorMessage
}
return Response.error<T>(responseBody, rawResponse)
}
}

View File

@@ -40,7 +40,7 @@ RETROFIT_VERSION = 2.9.0
OKHTTP_VERSION = 4.9.0
MOKITO_INLINE_VERSION = 2.13.0
CORE_TEST_VERSION = 2.2.0
MOCKK_VERSION = 1.10.5
MOCKK_VERSION = 1.13.12
TEST_JUNIT_VERSION = 1.2.0
TEST_RUNNER_VERSION = 1.5.2
ESPRESSO_VERSION = 3.6.0