My Android application uses AWS Cognito and Amplify Auth SDK for authentication and I'm trying to write JUnit test cases for login/signup flows. I'm using Mockito framework to mock the classes.
I started with login, my login model looks like this
class LoginService(val auth: AuthCategory) {
fun login(username: String, password: String): MutableLiveData<Login> {
val liveData = MutableLiveData<Login>()
auth.signIn(username, password,
{ result ->
liveData.postValue(Login(result, null))
},
{ error ->
liveData.postValue(Login(null, error))
}
)
return liveData
}
}
And my viewmodel calls it this way
class LoginViewModel : ViewModel() {
val loginService = LoginService(Amplify.Auth)
fun login(username: String, password: String): MutableLiveData<Login> {
return loginService.login(username, password)
}
}
And my test case looks like this
lateinit var auth: AuthCategory
lateinit var loginService: LoginService
@Before
fun onSetup() {
auth = mock(Amplify.Auth::class.java)
loginService = LoginService(auth)
}
@Test
fun loginTest() {
val authSignIn: Consumer<*>? = mock(Consumer::class.java)
val authEx: Consumer<*> = mock(Consumer::class.java)
`when`(
auth.signIn(
anyString(), anyString(),
authSignIn as Consumer<AuthSignInResult>, authEx as Consumer<AuthException>
)
)
loginService.login("username", "password").observeForever {
assertTrue(it.result?.isSignInComplete!!)
}
}
Please help me validate this approach,
I'm trying to find out a way to trigger AuthSignInResult and AuthException of Auth.signIn() method so that I would assert if signin is successful or there is an error.
I'm very new to AWS Amplify and Cognito environment, A suggestion/reference to do this in correct way would be highly appreciated. Thanks in advance.
There are a couple ways you can encourage testability with Amplify Android. Of the two below, I would definitely start with the first approach.
Use the category interfaces
This is a "unit test" level approach.
Amplify.Authimplements theAuthCategoryBehaviorinterface. So, if you change all of your code to use that interface, you can just mock it.Say you have some class which uses Auth as a dependency:
Now, in your production code, you'd have your Dependency Injection code do something like this:
addPlugin(AWSCognitoAuthPlugin()),Ampify.configure(...), etc.)YourClass, built fromYourClass(auth = Amplify.Auth)However in your test code, you can build an instance of
YourClassusing a mock of the Amplify Auth stuff:With that, you can specify how it should behave under test conditions:
Use OkHttp's
MockWebServerThis is more of a "component" or "integration" level approach. Here, we'll use a
MockWebServerinstance to return canned responses from a fake Cognito server.In this flow, you're using all of the real Amplify library code, in both production and in test. Just making believe you can control Cognito's responses to the client.
To do this, you should view the actual HTTP responses in your Android Studio's Network Monitor tab. Then, arrange that content into the test code below.
Have left a few details unspecified in this second example, but hopefully it's enough to set you in a working direction.