Skip to content

Instantly share code, notes, and snippets.

@michaelbukachi
Created July 24, 2018 10:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save michaelbukachi/594f34403f64158792f5810a9903a829 to your computer and use it in GitHub Desktop.
Save michaelbukachi/594f34403f64158792f5810a9903a829 to your computer and use it in GitHub Desktop.
Mocking of asynchronous call
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);
}
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()
}
}
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