diff --git a/.idea/caches/build_file_checksums.ser b/.idea/caches/build_file_checksums.ser
new file mode 100644
index 0000000..8d16675
Binary files /dev/null and b/.idea/caches/build_file_checksums.ser differ
diff --git a/.idea/encodings.xml b/.idea/encodings.xml
new file mode 100644
index 0000000..15a15b2
--- /dev/null
+++ b/.idea/encodings.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
index 3963879..5745957 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -5,26 +5,37 @@
-
+
diff --git a/.idea/modules.xml b/.idea/modules.xml
index 5d0b7d5..9bd7a7e 100644
--- a/.idea/modules.xml
+++ b/.idea/modules.xml
@@ -2,9 +2,11 @@
+
+
\ No newline at end of file
diff --git a/README.md b/README.md
index ceeae4f..aaf3901 100644
--- a/README.md
+++ b/README.md
@@ -17,8 +17,8 @@ https://home.openweathermap.org/api_keys
### Tools / Libs Utilized
- Jetbrains Kotlin : https://kotlinlang.org/
-- Toothpick Dependency Injection : https://github.com/stephanenicolas/toothpick
+- Toothpick Dependency Injection 2.1.0 : https://github.com/stephanenicolas/toothpick
- RxJava 2 / RxAndroid : https://github.com/ReactiveX/RxJava
- Retrofit 2 : http://square.github.io/retrofit/
- Picasso : http://square.github.io/picasso/
-- EasyMock : http://easymock.org/
+- Mockk : https://github.com/mockk/mockk
diff --git a/app/build.gradle b/app/build.gradle
index c2dd176..5dd4237 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -1,17 +1,18 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
+apply plugin: 'kotlin-kapt'
android {
- compileSdkVersion 25
- buildToolsVersion "25.0.0"
+ compileSdkVersion 28
+ buildToolsVersion "28.0.3"
defaultConfig {
applicationId "weather.ekamp.com.weatherappkotlin"
minSdkVersion 23
- targetSdkVersion 25
+ targetSdkVersion 28
versionCode 1
versionName "1.0"
- testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
@@ -32,33 +33,28 @@ android {
}
dependencies {
- compile fileTree(dir: 'libs', include: ['*.jar'])
- compile "com.android.support:appcompat-v7:$SUPPORT_LIBS_VERSION"
- compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
- compile "com.squareup.picasso:picasso:$PICASSO_VERSION"
- compile "com.squareup.retrofit2:retrofit:$RETROFIT_VERSION"
- compile "com.squareup.retrofit2:converter-moshi:$RETROFIT_VERSION"
- compile "com.squareup.retrofit2:adapter-rxjava2:$RETROFIT_VERSION"
- compile "io.reactivex.rxjava2:rxjava:$RX_JAVA_VERSION"
- compile "io.reactivex.rxjava2:rxandroid:$RX_ANDROID_VERSION"
- compile "com.google.android.gms:play-services-location:$PLAY_SERVICES_VERSION"
- compile "com.github.stephanenicolas.toothpick:toothpick-runtime:$TOOTHPICK_VERSION"
- compile "com.github.stephanenicolas.toothpick:smoothie:$TOOTHPICK_VERSION"
- kapt "com.github.stephanenicolas.toothpick:toothpick-compiler:$TOOTHPICK_VERSION"
- testCompile "com.github.stephanenicolas.toothpick:toothpick-testing:$TOOTHPICK_VERSION"
- testCompile "junit:junit:$JUNIT_VERSION"
- testCompile "org.easymock:easymock:$EASYMOCK_VERSION"
+ implementation fileTree(dir: 'libs', include: ['*.jar'])
+ implementation "androidx.appcompat:appcompat:1.0.2"
+ implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.31"
+ implementation "com.squareup.picasso:picasso:2.71828"
+ implementation "com.squareup.retrofit2:retrofit:2.6.0"
+ implementation "com.squareup.retrofit2:converter-moshi:2.6.0"
+ implementation "com.squareup.retrofit2:adapter-rxjava2:2.6.0"
+ implementation "io.reactivex.rxjava2:rxjava:2.2.10"
+ implementation "io.reactivex.rxjava2:rxandroid:2.1.1"
+ implementation "com.google.android.gms:play-services-location:17.0.0"
+
+ implementation 'com.github.stephanenicolas.toothpick:toothpick-runtime:2.1.0'
+ implementation 'com.github.stephanenicolas.toothpick:smoothie:2.1.0'
+ implementation "com.github.stephanenicolas.toothpick:smoothie-androidx:2.1.0"
+ kapt "com.github.stephanenicolas.toothpick:toothpick-compiler:2.1.0"
+ testImplementation "com.github.stephanenicolas.toothpick:toothpick-testing-junit4:2.1.0"
+ testImplementation "junit:junit:4.12"
+ testImplementation "io.mockk:mockk:1.9.3"
}
kapt {
- generateStubs = true
-
arguments {
arg("toothpick_registry_package_name", "weather.ekamp.com.weatherappkotlin")
- arg("toothpick_registry_children_package_names", "toothpick.smoothie")
}
-}
-
-repositories {
- mavenCentral()
-}
+}
\ No newline at end of file
diff --git a/app/src/main/java/weather/ekamp/com/weatherappkotlin/WeatherApplication.kt b/app/src/main/java/weather/ekamp/com/weatherappkotlin/WeatherApplication.kt
index 622cc7d..092698f 100644
--- a/app/src/main/java/weather/ekamp/com/weatherappkotlin/WeatherApplication.kt
+++ b/app/src/main/java/weather/ekamp/com/weatherappkotlin/WeatherApplication.kt
@@ -1,23 +1,13 @@
package weather.ekamp.com.weatherappkotlin
import android.app.Application
-import toothpick.smoothie.module.SmoothieApplicationModule
import toothpick.Toothpick
+import toothpick.smoothie.module.SmoothieApplicationModule
import weather.ekamp.com.weatherappkotlin.model.inject.WeatherApplicationModule
-import toothpick.configuration.Configuration.forDevelopment
-import toothpick.configuration.Configuration.forProduction
-import toothpick.registries.FactoryRegistryLocator
-import toothpick.registries.MemberInjectorRegistryLocator
-import toothpick.Toothpick.setConfiguration
-
class WeatherApplication : Application() {
override fun onCreate() {
super.onCreate()
- val configuration = if (BuildConfig.DEBUG) forDevelopment() else forProduction()
- setConfiguration(configuration.disableReflection())
- FactoryRegistryLocator.setRootRegistry(FactoryRegistry())
- MemberInjectorRegistryLocator.setRootRegistry(MemberInjectorRegistry())
val appScope = Toothpick.openScope(this)
appScope.installModules(SmoothieApplicationModule(this), WeatherApplicationModule(this))
diff --git a/app/src/main/java/weather/ekamp/com/weatherappkotlin/model/location/LocationPermissionManager.kt b/app/src/main/java/weather/ekamp/com/weatherappkotlin/model/location/LocationPermissionManager.kt
index 25acd56..72fe61a 100644
--- a/app/src/main/java/weather/ekamp/com/weatherappkotlin/model/location/LocationPermissionManager.kt
+++ b/app/src/main/java/weather/ekamp/com/weatherappkotlin/model/location/LocationPermissionManager.kt
@@ -4,8 +4,8 @@ import android.Manifest
import android.app.Activity
import android.app.Application
import android.content.pm.PackageManager
-import android.support.v4.app.ActivityCompat
-import android.support.v4.content.ContextCompat
+import androidx.core.app.ActivityCompat
+import androidx.core.content.ContextCompat
import javax.inject.Inject
import javax.inject.Singleton
diff --git a/app/src/main/java/weather/ekamp/com/weatherappkotlin/model/location/UserLocationManager.kt b/app/src/main/java/weather/ekamp/com/weatherappkotlin/model/location/UserLocationManager.kt
index 8f5ab59..b1d35f7 100644
--- a/app/src/main/java/weather/ekamp/com/weatherappkotlin/model/location/UserLocationManager.kt
+++ b/app/src/main/java/weather/ekamp/com/weatherappkotlin/model/location/UserLocationManager.kt
@@ -23,7 +23,7 @@ class UserLocationManager {
fusedLocationClient.lastLocation
.addOnCompleteListener(activity) { task ->
if (task.isSuccessful && task.result != null) {
- locationUpdateListener.onLocationUpdated(task.result)
+ locationUpdateListener.onLocationUpdated(task.result!!)
} else {
Log.w(TAG, "getLastLocation:exception", task.exception)
locationUpdateListener.onLocationNotFound()
diff --git a/app/src/main/java/weather/ekamp/com/weatherappkotlin/model/networking/WeatherService.kt b/app/src/main/java/weather/ekamp/com/weatherappkotlin/model/networking/WeatherService.kt
index 748e83c..fcfa562 100644
--- a/app/src/main/java/weather/ekamp/com/weatherappkotlin/model/networking/WeatherService.kt
+++ b/app/src/main/java/weather/ekamp/com/weatherappkotlin/model/networking/WeatherService.kt
@@ -14,7 +14,7 @@ import javax.inject.Singleton
@Singleton
open class WeatherService @Inject constructor(var application: Application) {
- private val BASE_URL = "http://api.openweathermap.org/data/2.5/"
+ private val BASE_URL = "https://api.openweathermap.org/data/2.5/"
private val WEATHER_API_KEY = BuildConfig.WEATHER_API_KEY
private val TEMPERATURE_UNITS = "imperial"
private val sizeOfHttpCache : Long = 10 * 1024 * 1024 // 10 MiB
diff --git a/app/src/main/java/weather/ekamp/com/weatherappkotlin/view/ErrorDialog.kt b/app/src/main/java/weather/ekamp/com/weatherappkotlin/view/ErrorDialog.kt
index b59a83c..284382d 100644
--- a/app/src/main/java/weather/ekamp/com/weatherappkotlin/view/ErrorDialog.kt
+++ b/app/src/main/java/weather/ekamp/com/weatherappkotlin/view/ErrorDialog.kt
@@ -1,30 +1,30 @@
package weather.ekamp.com.weatherappkotlin.view
import android.os.Bundle
-import android.support.v4.app.DialogFragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
+import androidx.fragment.app.DialogFragment
+import kotlinx.android.synthetic.main.error_dialog.*
import weather.ekamp.com.weatherappkotlin.R
-import kotlinx.android.synthetic.main.error_dialog.*;
class ErrorDialog : DialogFragment() {
- lateinit private var message : String
+ lateinit private var message: String
companion object {
- fun newInstance(message : String) : ErrorDialog {
+ fun newInstance(message: String): ErrorDialog {
var newInstance = ErrorDialog()
newInstance.message = message
return newInstance
}
}
- override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? {
- return inflater?.inflate(R.layout.error_dialog, container)
+ override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
+ return inflater.inflate(R.layout.error_dialog, container)
}
- override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
confirmationButton.setOnClickListener {
dismiss()
}
diff --git a/app/src/main/java/weather/ekamp/com/weatherappkotlin/view/Landing.kt b/app/src/main/java/weather/ekamp/com/weatherappkotlin/view/Landing.kt
index e019cf5..611c9e9 100644
--- a/app/src/main/java/weather/ekamp/com/weatherappkotlin/view/Landing.kt
+++ b/app/src/main/java/weather/ekamp/com/weatherappkotlin/view/Landing.kt
@@ -1,10 +1,12 @@
package weather.ekamp.com.weatherappkotlin.view
+import android.annotation.SuppressLint
import android.location.Location
-import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.view.animation.Animation
+import android.view.animation.AnimationUtils
+import androidx.appcompat.app.AppCompatActivity
import com.squareup.picasso.Picasso
import kotlinx.android.synthetic.main.activity_main.*
import toothpick.Scope
@@ -14,14 +16,15 @@ import weather.ekamp.com.weatherappkotlin.model.location.UserLocationManager
import weather.ekamp.com.weatherappkotlin.model.parsers.WeatherDescription
import weather.ekamp.com.weatherappkotlin.presenter.LandingPresenter
import javax.inject.Inject
-import android.view.animation.AnimationUtils
class Landing : AppCompatActivity(), LandingView {
- @Inject lateinit var presenter : LandingPresenter
- @Inject lateinit var userLocationManager : UserLocationManager
- lateinit private var errorDialog : ErrorDialog
- lateinit private var activityScope : Scope
+ @Inject
+ lateinit var presenter: LandingPresenter
+ @Inject
+ lateinit var userLocationManager: UserLocationManager
+ lateinit private var errorDialog: ErrorDialog
+ lateinit private var activityScope: Scope
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -37,18 +40,14 @@ class Landing : AppCompatActivity(), LandingView {
weather_description.text = weatherDescription.getWeatherInformation().description
temperature.text = weatherDescription.main.temp
var weatherIconPath = weatherDescription.getIconUrlPath()
- Picasso.with(this).
- load(weatherIconPath).
- fit().
- placeholder(R.drawable.cloud).
- error(R.drawable.cloud).
- into(weather_representation)
+ Picasso.get().load(weatherIconPath).fit().placeholder(R.drawable.cloud).error(R.drawable.cloud).into(weather_representation)
}
- override fun displayUserLocation(userLocationForDisplay : String) {
+ override fun displayUserLocation(userLocationForDisplay: String) {
user_location.text = userLocationForDisplay
}
+ @SuppressLint("ResourceType")
override fun displayLoadingIndicator() {
loading_indicator.visibility = View.VISIBLE
weather_description.visibility = View.GONE
@@ -56,7 +55,7 @@ class Landing : AppCompatActivity(), LandingView {
weather_representation.visibility = View.GONE
sync_button.animation?.let {
sync_button.animation.repeatCount = Animation.INFINITE
- } ?:run {
+ } ?: run {
val rotation = AnimationUtils.loadAnimation(this, R.animator.sync_rotator)
rotation.repeatCount = Animation.INFINITE
sync_button.startAnimation(rotation)
diff --git a/app/src/main/java/weather/ekamp/com/weatherappkotlin/view/Splash.kt b/app/src/main/java/weather/ekamp/com/weatherappkotlin/view/Splash.kt
index 6f53f69..eb2d7b2 100644
--- a/app/src/main/java/weather/ekamp/com/weatherappkotlin/view/Splash.kt
+++ b/app/src/main/java/weather/ekamp/com/weatherappkotlin/view/Splash.kt
@@ -3,8 +3,8 @@ package weather.ekamp.com.weatherappkotlin.view
import android.app.Activity
import android.content.Intent
import android.content.pm.PackageManager
-import android.support.v7.app.AppCompatActivity
import android.os.Bundle
+import androidx.appcompat.app.AppCompatActivity
import toothpick.Scope
import toothpick.Toothpick
import weather.ekamp.com.weatherappkotlin.R
@@ -15,10 +15,11 @@ import javax.inject.Inject
class Splash : AppCompatActivity(), SplashView {
val ERROR_DIALOG_TAG = "location_permission_error_dialog"
- @Inject lateinit var presenter : SplashPresenter
- lateinit var activityScope : Scope
+ @Inject
+ lateinit var presenter: SplashPresenter
+ lateinit var activityScope: Scope
- lateinit var errorDialog : ErrorDialog
+ lateinit var errorDialog: ErrorDialog
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
activityScope = Toothpick.openScopes(application, this)
diff --git a/app/src/test/java/weather/ekamp/com/weatherappkotlin/model/NetworkStatusUtilTest.kt b/app/src/test/java/weather/ekamp/com/weatherappkotlin/model/NetworkStatusUtilTest.kt
index 7664952..a842a8b 100644
--- a/app/src/test/java/weather/ekamp/com/weatherappkotlin/model/NetworkStatusUtilTest.kt
+++ b/app/src/test/java/weather/ekamp/com/weatherappkotlin/model/NetworkStatusUtilTest.kt
@@ -4,10 +4,10 @@ import android.app.Application
import android.content.Context
import android.net.ConnectivityManager
import android.net.NetworkInfo
-import org.easymock.EasyMock.expect
-import org.easymock.EasyMockRule
-import org.easymock.EasyMockSupport
-import org.easymock.Mock
+import io.mockk.MockKAnnotations
+import io.mockk.every
+import io.mockk.impl.annotations.InjectMockKs
+import io.mockk.impl.annotations.MockK
import org.hamcrest.CoreMatchers.`is`
import org.hamcrest.MatcherAssert.assertThat
import org.junit.Before
@@ -15,24 +15,25 @@ import org.junit.Rule
import org.junit.Test
import toothpick.testing.ToothPickRule
import weather.ekamp.com.weatherappkotlin.model.networking.NetworkStatusUtil
-import javax.inject.Inject
-class NetworkStatusUtilTest : EasyMockSupport() {
+class NetworkStatusUtilTest {
- var easyMockRule = EasyMockRule(this)
+ val toothpickRule = ToothPickRule(this)
@Rule get
- var toothpickRule = ToothPickRule(this)
- @Rule get
-
- @Mock internal lateinit var application : Application
- @Mock internal lateinit var connectivityManager : ConnectivityManager
- @Mock internal lateinit var networkInfo : NetworkInfo
+ @MockK
+ internal lateinit var application: Application
+ @MockK
+ internal lateinit var connectivityManager: ConnectivityManager
+ @MockK
+ internal lateinit var networkInfo: NetworkInfo
- @Inject lateinit var networkStatusUtil : NetworkStatusUtil
+ @InjectMockKs
+ lateinit var networkStatusUtil: NetworkStatusUtil
@Before
fun setup() {
+ MockKAnnotations.init(this)
toothpickRule.setScopeName(application)
toothpickRule.inject(this)
}
@@ -40,16 +41,14 @@ class NetworkStatusUtilTest : EasyMockSupport() {
@Test
fun test_internetConnectivityAvailable_returnsTrue_when_networkInfoIsConnectedOrConnectingReturnsTrue() {
//GIVEN
- expect(application.getSystemService(Context.CONNECTIVITY_SERVICE)).andReturn(connectivityManager)
- expect(connectivityManager.activeNetworkInfo).andReturn(networkInfo)
- expect(networkInfo.isConnectedOrConnecting).andReturn(true)
- replayAll()
+ every { application.getSystemService(Context.CONNECTIVITY_SERVICE) } returns connectivityManager
+ every { connectivityManager.activeNetworkInfo } returns networkInfo
+ every { networkInfo.isConnectedOrConnecting } returns true
//WHEN
val result = networkStatusUtil.internetConnectivityAvailable()
//THEN
- verifyAll()
assertThat(result, `is`(true))
}
}
diff --git a/app/src/test/java/weather/ekamp/com/weatherappkotlin/presenter/LandingPresenterTest.kt b/app/src/test/java/weather/ekamp/com/weatherappkotlin/presenter/LandingPresenterTest.kt
index ac7bbf6..351043e 100644
--- a/app/src/test/java/weather/ekamp/com/weatherappkotlin/presenter/LandingPresenterTest.kt
+++ b/app/src/test/java/weather/ekamp/com/weatherappkotlin/presenter/LandingPresenterTest.kt
@@ -2,115 +2,138 @@ package weather.ekamp.com.weatherappkotlin.presenter
import android.app.Application
import android.location.Location
+import io.mockk.MockKAnnotations
+import io.mockk.every
+import io.mockk.impl.annotations.InjectMockKs
+import io.mockk.impl.annotations.MockK
+import io.mockk.verifySequence
import io.reactivex.Single
-import org.easymock.*
-import org.easymock.EasyMock.expect
+import io.reactivex.android.plugins.RxAndroidPlugins
+import io.reactivex.schedulers.Schedulers
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import toothpick.testing.ToothPickRule
import weather.ekamp.com.weatherappkotlin.model.networking.WeatherService
+import weather.ekamp.com.weatherappkotlin.model.parsers.Weather
import weather.ekamp.com.weatherappkotlin.model.parsers.WeatherDescription
import weather.ekamp.com.weatherappkotlin.view.LandingView
-import javax.inject.Inject
-class LandingPresenterTest : EasyMockSupport() {
+class LandingPresenterTest {
- var easyMockRule = EasyMockRule(this)
- @Rule get
-
- var toothpickRule = ToothPickRule(this)
- @Rule get
+ val toothpickRule = ToothPickRule(this)
+ @Rule get
private val TEST_MESSAGE = "Error"
private val TEST_LOCATION_LAT_NUM = 40.758895
private val TEST_LOCATION_LNG_NUM = -73.9873197
- @Mock internal lateinit var landingView : LandingView
- @Mock internal lateinit var weatherService : WeatherService
- @Mock internal lateinit var location : Location
- @Mock internal lateinit var application : Application
- @Mock internal lateinit var single : Single
- @Mock internal lateinit var weatherDescription : WeatherDescription
- @Mock internal lateinit var throwable : Throwable
-
- @Inject lateinit var landingPresenter : LandingPresenter
+ @MockK
+ internal lateinit var landingView: LandingView
+ @MockK
+ internal lateinit var weatherService: WeatherService
+ @MockK
+ internal lateinit var location: Location
+ @MockK
+ internal lateinit var application: Application
+ @MockK
+ internal lateinit var single: Single
+ @MockK
+ internal lateinit var weatherDescription: WeatherDescription
+ @MockK
+ internal lateinit var throwable: Throwable
+
+ @InjectMockKs
+ lateinit var landingPresenter: LandingPresenter
@Before
fun setup() {
+ MockKAnnotations.init(this)
toothpickRule.setScopeName(application)
toothpickRule.inject(this)
landingPresenter.landingView = landingView
+ RxAndroidPlugins.setInitMainThreadSchedulerHandler { _ -> Schedulers.trampoline() }
}
@Test
fun test_onAttachView_collectsUsersLocation_and_displaysLoadingIndicator() {
//GIVEN
- expect(landingView.getUsersLocation())
- expect(landingView.displayLoadingIndicator())
- replayAll()
+ every { (landingView.getUsersLocation()) } returns Unit
+ every { (landingView.displayLoadingIndicator()) } returns Unit
//WHEN
landingPresenter.onAttachView(landingView)
//THEN
- verifyAll()
+ verifySequence {
+ landingView.displayLoadingIndicator()
+ landingView.getUsersLocation()
+ }
}
@Test
fun test_createAndRegisterWeatherSubscription_createsSubscriptionToWeatherService() {
//GIVEN
- expect(location.latitude).andReturn(TEST_LOCATION_LAT_NUM)
- expect(location.longitude).andReturn(TEST_LOCATION_LNG_NUM)
- expect(weatherService.getWeatherInformation(TEST_LOCATION_LAT_NUM.toFloat().toString(), TEST_LOCATION_LNG_NUM.toFloat().toString())).andReturn(single)
- replayAll()
+ every { (location.latitude) } returns (TEST_LOCATION_LAT_NUM)
+ every { (location.longitude) } returns (TEST_LOCATION_LNG_NUM)
+ val weatherArray: Array = arrayOf(Weather("Rennes", "Soleil", "01d.png"))
+ val temperatureInformation: WeatherDescription.TemperatureInformation = WeatherDescription.TemperatureInformation("15", "50", "10", "18")
+ val single: Single = Single.just(WeatherDescription(weatherArray, temperatureInformation))
+ every { (weatherService.getWeatherInformation(TEST_LOCATION_LAT_NUM.toFloat().toString(), TEST_LOCATION_LNG_NUM.toFloat().toString())) } returns (single)
//WHEN
landingPresenter.createAndRegisterWeatherSubscription(location)
//THEN
- verifyAll()
+ verifySequence {
+ weatherService.getWeatherInformation(any(), any())
+ }
}
@Test
fun test_createLocationSubscription_getsUserLocationFromLandingView() {
//GIVEN
- expect(landingView.getUsersLocation())
- replayAll()
+ every { (landingView.getUsersLocation()) } returns Unit
//WHEN
landingPresenter.createLocationSubscription()
//THEN
- verifyAll()
+ verifySequence {
+ landingView.getUsersLocation()
+ }
}
@Test
fun test_onWeatherCollected_hidesProgressIndicatorAndShowsWeatherInformation() {
//GIVEN
- expect(landingView.hideLoadingIndicator())
- expect(landingView.displayCurrentWeather(weatherDescription))
- replayAll()
+ every { (landingView.hideLoadingIndicator()) } returns Unit
+ every { (landingView.displayCurrentWeather(weatherDescription)) } returns Unit
//WHEN
landingPresenter.onWeatherCollected(weatherDescription)
//THEN
- verifyAll()
+ verifySequence {
+ landingView.hideLoadingIndicator()
+ landingView.displayCurrentWeather(weatherDescription)
+ }
}
@Test
fun test_onWeatherCollectionFailure_hidesProgressIndicatorAndShowsError() {
//GIVEN
- expect(landingView.hideLoadingIndicator())
- expect(landingView.displayErrorToUser(TEST_MESSAGE))
- expect(throwable.localizedMessage).andReturn(TEST_MESSAGE)
- replayAll()
+ every { (landingView.hideLoadingIndicator()) } returns Unit
+ every { (landingView.displayErrorToUser(TEST_MESSAGE)) } returns Unit
+ every { (throwable.localizedMessage) } returns (TEST_MESSAGE)
//WHEN
landingPresenter.onWeatherCollectionFailure(throwable)
//THEN
- verifyAll()
+ verifySequence {
+ landingView.hideLoadingIndicator()
+ landingView.displayErrorToUser(TEST_MESSAGE)
+ }
}
}
diff --git a/app/src/test/java/weather/ekamp/com/weatherappkotlin/presenter/SplashPresenterTest.kt b/app/src/test/java/weather/ekamp/com/weatherappkotlin/presenter/SplashPresenterTest.kt
index 7059a85..681c55e 100644
--- a/app/src/test/java/weather/ekamp/com/weatherappkotlin/presenter/SplashPresenterTest.kt
+++ b/app/src/test/java/weather/ekamp/com/weatherappkotlin/presenter/SplashPresenterTest.kt
@@ -2,8 +2,14 @@ package weather.ekamp.com.weatherappkotlin.presenter
import android.app.Activity
import android.app.Application
-import org.easymock.*
-import org.easymock.EasyMock.expect
+import io.mockk.MockKAnnotations
+import io.mockk.every
+import io.mockk.impl.annotations.InjectMockKs
+import io.mockk.impl.annotations.MockK
+import io.mockk.verifySequence
+import io.reactivex.android.plugins.RxAndroidPlugins
+import io.reactivex.schedulers.Schedulers
+import org.hamcrest.CoreMatchers.`is`
import org.junit.Assert.assertThat
import org.junit.Before
import org.junit.Rule
@@ -11,101 +17,101 @@ import org.junit.Test
import toothpick.testing.ToothPickRule
import weather.ekamp.com.weatherappkotlin.model.location.LocationPermissionManager
import weather.ekamp.com.weatherappkotlin.view.SplashView
-import javax.inject.Inject
-
-import org.hamcrest.CoreMatchers.`is`
-
-class SplashPresenterTest : EasyMockSupport() {
- val easyMockRule = EasyMockRule(this)
- @Rule get
+class SplashPresenterTest {
val toothpickRule = ToothPickRule(this)
- @Rule get
+ @Rule get
- @Mock lateinit var splashView : SplashView
- @Mock lateinit var activity : Activity
- @Mock lateinit var application : Application
- @Mock lateinit var locationPermissionManager : LocationPermissionManager
+ @MockK
+ lateinit var splashView: SplashView
+ @MockK
+ lateinit var activity: Activity
+ @MockK
+ lateinit var application: Application
+ @MockK
+ lateinit var locationPermissionManager: LocationPermissionManager
- @Inject lateinit var splashPresenter : SplashPresenter
+ @InjectMockKs
+ lateinit var splashPresenter: SplashPresenter
@Before
fun setup() {
+ MockKAnnotations.init(this)
toothpickRule.setScopeName(application)
toothpickRule.inject(this)
splashPresenter.splashView = splashView
+ RxAndroidPlugins.setInitMainThreadSchedulerHandler { _ -> Schedulers.trampoline() }
}
@Test
fun test_onAttachView_landingIsStarted_when_locationPermissionHasBeenGranted() {
//GIVEN
- expect(splashView.startLanding())
- expect(locationPermissionManager.hasLocationPermissionBeenGranted()).andReturn(true)
- replayAll()
+ every { splashView.startLanding() } returns Unit
+ every { locationPermissionManager.hasLocationPermissionBeenGranted() } returns true
//WHEN
splashPresenter.onAttachView(splashView)
//THEN
- verifyAll()
+ verifySequence {
+ splashView.startLanding()
+ }
}
@Test
fun test_onAttachView_locationPermissionIsRequested_when_locationPermissionHasNotBeenGranted() {
//GIVEN
- expect(locationPermissionManager.hasLocationPermissionBeenGranted()).andReturn(false)
- expect(locationPermissionManager.requestLocationPermission(activity))
- expect(splashView.getActivityReference()).andReturn(activity)
- replayAll()
+ every { locationPermissionManager.hasLocationPermissionBeenGranted() } returns false
+ every { locationPermissionManager.requestLocationPermission(activity) } returns Unit
+ every { splashView.getActivityReference() } returns activity
//WHEN
splashPresenter.onAttachView(splashView)
//THEN
- verifyAll()
+ verifySequence {
+ splashView.getActivityReference()
+ }
}
@Test
fun test_checkIfStartupComplete_returns_true_when_locationPermissionHasBeenGranted() {
//GIVEN
- expect(locationPermissionManager.hasLocationPermissionBeenGranted()).andReturn(true)
- replayAll()
+ every { locationPermissionManager.hasLocationPermissionBeenGranted() } returns true
//WHEN
val result = splashPresenter.checkIfStartupComplete()
//THEN
- verifyAll()
assertThat(result, `is`(true))
}
@Test
fun test_checkIfStartupComplete_returns_false_when_locationPermissionHasNotBeenGranted() {
//GIVEN
- expect(locationPermissionManager.hasLocationPermissionBeenGranted()).andReturn(false)
- expect(locationPermissionManager.requestLocationPermission(activity))
- expect(splashView.getActivityReference()).andReturn(activity)
- replayAll()
+ every { locationPermissionManager.hasLocationPermissionBeenGranted() } returns false
+ every { locationPermissionManager.requestLocationPermission(activity) } returns Unit
+ every { splashView.getActivityReference() } returns activity
//WHEN
val result = splashPresenter.checkIfStartupComplete()
//THEN
- verifyAll()
assertThat(result, `is`(false))
}
@Test
fun test_onLocationPermissionDenied_showsRationaleToUser() {
//GIVEN
- expect(splashView.showLocationPermissionRationaleDialog())
- replayAll()
+ every { splashView.showLocationPermissionRationaleDialog() } returns Unit
//WHEN
splashPresenter.onLocationPermissionDenied()
//THEN
- verifyAll()
+ verifySequence {
+ splashView.showLocationPermissionRationaleDialog()
+ }
}
}
diff --git a/build.gradle b/build.gradle
index 608180a..62cf778 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,12 +1,13 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
- ext.kotlin_version = '1.1.2-4'
+ ext.kotlin_version = '1.3.31'
repositories {
jcenter()
+ google()
}
dependencies {
- classpath 'com.android.tools.build:gradle:2.2.3'
+ classpath 'com.android.tools.build:gradle:3.4.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong
@@ -17,6 +18,8 @@ buildscript {
allprojects {
repositories {
jcenter()
+ google()
+ mavenCentral()
}
}
diff --git a/gradle.properties b/gradle.properties
index 72c512c..537eee0 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,11 +1,13 @@
org.gradle.jvmargs=-Xmx1536m
-PLAY_SERVICES_VERSION=11.0.2
-SUPPORT_LIBS_VERSION=25.3.1
-TOOTHPICK_VERSION=1.0.8
+PLAY_SERVICES_VERSION=16.0.0
+SUPPORT_LIBS_VERSION=27.1.1
+TOOTHPICK_VERSION=1.1.3
EASYMOCK_VERSION=3.4
JUNIT_VERSION=4.12
-RX_ANDROID_VERSION=2.0.1
-RX_JAVA_VERSION=2.1.0
+RX_ANDROID_VERSION=2.1.1
+RX_JAVA_VERSION=2.1.1
RETROFIT_VERSION=2.3.0
PICASSO_VERSION=2.5.2
+android.useAndroidX=true
+android.enableJetifier=true
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 04e285f..34420ed 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Mon Dec 28 10:00:20 PST 2015
+#Fri Jun 21 11:41:26 CEST 2019
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip