Created
July 24, 2018 10:08
-
-
Save michaelbukachi/594f34403f64158792f5810a9903a829 to your computer and use it in GitHub Desktop.
Mocking of asynchronous call
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public static class Auth { | |
private static Auth auth; | |
private static String baseUrl; | |
private String message = null; | |
public static Auth getInstance(String base) { | |
baseUrl = base; | |
if (auth == null) { | |
auth = new Auth(); | |
} | |
return auth; | |
} | |
public void authenticate(String username, String password, final AuthCompletedListener listener) { | |
Thread thread = new Thread(() -> { | |
boolean success = true; | |
try { | |
success = login(username, password); | |
} catch (IOException e) { | |
success = false; | |
message = "Unable to connect"; | |
} catch (Exception e) { | |
success = false; | |
message = "An error occurred"; | |
} finally { | |
listener.onCompleted(success, message); | |
} | |
}); | |
thread.start(); | |
} | |
public interface AuthCompletedListener { | |
void onCompleted(boolean success, String message); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package dita.dev.myportal.ui.login | |
import android.app.Application | |
import android.arch.lifecycle.MutableLiveData | |
import android.arch.lifecycle.Observer | |
import android.graphics.drawable.Drawable | |
import android.view.View | |
import com.crashlytics.android.answers.Answers | |
import com.crashlytics.android.answers.LoginEvent | |
import dita.dev.daystarportal_wrapper.Portal | |
import dita.dev.myportal.Preferences | |
import dita.dev.myportal.model.repo.AppRepository | |
import dita.dev.myportal.ui.base.v2.BaseAndroidViewModel | |
import dita.dev.myportal.ui.base.v2.SingleLiveEvent | |
import dita.dev.myportal.utils.NetworkUtils | |
import javax.inject.Inject | |
class LoginViewModel @Inject | |
internal constructor(application: Application, val auth: Portal.Auth, val repository: AppRepository) : | |
BaseAndroidViewModel(application) { | |
val isLoading = MutableLiveData<Boolean>() | |
var username = "" | |
var password = "" | |
val background = MutableLiveData<Drawable>() | |
val goToMain = SingleLiveEvent<Void>() | |
val task = SetBackground(getApplication()) | |
private val backgroundObserver = Observer<Drawable> { | |
background.postValue(it) | |
} | |
init { | |
task.background.observeForever(backgroundObserver) | |
} | |
override fun onCleared() { | |
super.onCleared() | |
task.background.removeObserver(backgroundObserver) | |
} | |
fun start() { | |
setBackgroundImage() | |
repository.clear() | |
} | |
fun validateCredentials(view: View) { | |
if (username.isBlank() || password.isBlank()) { | |
showSnackbar("Please fill both fields"); | |
return; | |
} | |
// UIUtils.hideKeyboard(getApplication()); | |
if (!isNetworkUp()) { | |
showSnackbar("No internet connection"); | |
return; | |
} | |
isLoading.value = true | |
authenticate() | |
} | |
private fun isNetworkUp() : Boolean { | |
return NetworkUtils.isNetworkConnected(getApplication()) | |
} | |
private fun authenticate() { | |
auth.authenticate(username, password) { success, message -> | |
isLoading.postValue(false) | |
if (success) { | |
Preferences.setString(getApplication(), "username", username) | |
Preferences.setString(getApplication(), "password", password) | |
Preferences.setBoolean(getApplication(), "loggedIn", true) | |
Answers.getInstance().logLogin(LoginEvent().putSuccess(true)) | |
goToMain.postValue(null) | |
} else { | |
showSnackbar(message) | |
} | |
} | |
} | |
private fun setBackgroundImage() { | |
task.execute() | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package dita.dev.myportal.ui.login | |
import android.app.Application | |
import android.arch.core.executor.testing.InstantTaskExecutorRule | |
import android.view.View | |
import dita.dev.daystarportal_wrapper.Portal | |
import dita.dev.myportal.model.repo.AppRepository | |
import io.mockk.MockKAnnotations | |
import io.mockk.every | |
import io.mockk.impl.annotations.InjectMockKs | |
import io.mockk.impl.annotations.MockK | |
import io.mockk.spyk | |
import io.mockk.verify | |
import org.junit.Before | |
import org.junit.Rule | |
import org.junit.Test | |
import org.mockito.ArgumentCaptor | |
import org.mockito.ArgumentMatchers.any | |
import org.mockito.Captor | |
//import org.powermock.api.mockito.PowerMockito | |
//import org.powermock.api.mockito.PowerMockito.doReturn | |
//import org.powermock.api.mockito.PowerMockito.verifyPrivate | |
//import org.powermock.core.classloader.annotations.PrepareForTest | |
//import org.powermock.modules.junit4.PowerMockRunner | |
//@RunWith(PowerMockRunner::class) | |
//@PrepareForTest(LoginViewModel::class, AppRepository::class, NetworkUtils::class) | |
class LoginViewModelTest { | |
// @Rule @JvmField | |
// val mockitoRule = MockitoJUnit.rule() | |
@Rule @JvmField | |
val instantRule = InstantTaskExecutorRule() | |
@MockK | |
lateinit var app: Application | |
@MockK | |
lateinit var auth: Portal.Auth | |
@MockK | |
lateinit var repository: AppRepository | |
@MockK | |
lateinit var view: View | |
@InjectMockKs | |
lateinit var loginViewModel: LoginViewModel | |
lateinit var spyLoginViewModel: LoginViewModel | |
@Captor | |
lateinit var authListenerCaptor: ArgumentCaptor<Portal.Auth.AuthCompletedListener> | |
@Before | |
fun setup() { | |
MockKAnnotations.init(this) | |
spyLoginViewModel = spyk(loginViewModel, recordPrivateCalls = true) | |
} | |
@Test | |
fun `test for blank credentials`() { | |
spyLoginViewModel.validateCredentials(view) | |
verify { spyLoginViewModel invoke "showSnackbar" withArguments listOf("Please fill both fields") } | |
} | |
@Test | |
fun `test for no internet`() { | |
spyLoginViewModel.username = "user" | |
spyLoginViewModel.password = "pass" | |
every { spyLoginViewModel["isNetworkUp"]() } returns false | |
spyLoginViewModel.validateCredentials(view) | |
verify { spyLoginViewModel invoke "showSnackbar" withArguments listOf("No internet connection") } | |
} | |
@Test | |
fun `test failed login`() { | |
} | |
@Test | |
fun `test successful login`() { | |
spyLoginViewModel.username = "user" | |
spyLoginViewModel.password = "pass" | |
every { spyLoginViewModel["isNetworkUp"]() } returns true | |
val spyAuth = spyk(auth) | |
every { spyAuth.authenticate(spyLoginViewModel.username, spyLoginViewModel.password, any(Portal.Auth.AuthCompletedListener::class.java))} answers { | |
(invocation.args[0] as Portal.Auth.AuthCompletedListener).onCompleted(true, null) | |
} | |
spyLoginViewModel.validateCredentials(view) | |
verify { spyLoginViewModel["authenticate"]() } | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment