I've just started to do Unit testing in Kotlin using Mockk.
I'm trying to test the following function:
fun evaluatePredicate(regEx: String, passwordInserted: String) : Boolean {
return passwordInserted.matches(regEx.toRegex())
}
My test look like this:
#Test
fun evaluatePredicate_shouldContainLowerCase_trueExpected() {
//given
val regEx = ".*[a-z]+.*" //lower case
val password = "password"
every { password.matches(regEx.toRegex()) } returns true
every { SUT.evaluatePredicate(regEx, password) } returns true
//when
val evaluate = password.matches(regEx.toRegex())
val result = SUT.evaluatePredicate(regEx, password)
//then
assertEquals(evaluate, result)
}
But I'm getting :
io.mockk.MockKException: Missing calls inside every { ... } block.
at line:
every { password.matches(regEx.toRegex()) } returns true
I've tried to use Mockk Matcher any() instead of matches(regEx.toRegex()) but nothing changed.
I'm not sure if I'm using the right tools for the job here.
Any suggestion is welcome.
Related
i am trying to test out an email field in login screen. i want to change the following code using mockito. can it be done. pls help??
class EmailValidatorTest {
#Test
fun emailValidator_CorrectEmailSimple_ReturnsGood() {
val email = "name#email.com"
assertThat(EmailPasswordChecker.getEmailState(email)).isEqualTo(EmailState.GOOD)
}
#Test
fun emailValidator_CorrectEmailSubDomain_ReturnsGood() {
val email = "name#email.co.uk"
assertThat(EmailPasswordChecker.getEmailState(email)).isEqualTo(EmailState.GOOD)
}
#Test
fun emailValidator_InvalidEmailNoTld_ReturnsIncorrect() {
val email = "name#email"
assertThat(EmailPasswordChecker.getEmailState(email)).isEqualTo(EmailState.INCORRECT)
}
#Test
fun emailValidator_InvalidEmailDoubleDot_ReturnsIncorrect() {
val email = "name#email..com"
assertThat(EmailPasswordChecker.getEmailState(email)).isEqualTo(EmailState.INCORRECT)
}
#Test
fun emailValidator_InvalidEmailNoUsername_ReturnsIncorrect() {
val email = "#email.com"
assertThat(EmailPasswordChecker.getEmailState(email)).isEqualTo(EmailState.INCORRECT)
}
#Test
fun emailValidator_EmptyString_ReturnsEmpty() {
val email = ""
assertThat(EmailPasswordChecker.getEmailState(email)).isEqualTo(EmailState.EMPTY)
}
here is some more helper code->
object EmailPasswordChecker{
//some code that i cant share
}
enum class EmailState {
GOOD,
INCORRECT,
EMPTY
}
these are simple tests that i wrote using JUnit. but now i need to change them using mockito. can someone help me with the code? i am fairly new to testing so i am not exactly able to figure out how this framework is working.
#Composable
fun MyComposable(submit: (String) -> Unit) {
MyButton(title = "Submit") {
submit("Hello World!")
}
}
#Composable
fun MyButton(title: String, submit: (String) -> Unit) {
Button(onClick = submit) {
Text(text = title)
}
}
How can I unit test that submit were to be called?
While in the test I can set the submit result inside MyComposable, it never actually gets called when the test is being ran.
The test would look like this:
#Test
fun trySubmit_expectPrint() {
composeRule.setContent { GetDefaultScreen() }
//Too lazy to write the hasTestTag, but assume it gets the correct node.
composeRule.onNodeWithTag("MyComposable").performClick()
//Assertions here...
}
#Composable
private fun GetDefaultScreen() =
MyComposable() {
Log.d("TEST", "Submitting")
}
My end goal here is to have the scope of that composable in the test change a variable, in order to allow me to verify that that block was ran.
This is all under the assumption that we are still unable to Mock or Spy on final classes with an androidTest (UI test).
If that assumption is wrong, please correct me if there's a method in which I can do that.
I've since come to found something that works for me.
In the test function, just adding a value that should get changed by the callback, and then making an assertion on that value:
#Test
fun myTest() {
var testValue = ""
composeTestRule.setContent {
Button() { testValue = "Hello, World!" }
}
assertThat(testValue).equals("Hello, World!")
}
I am using:
val data = firestore.collection("add").document("departament").collection("anuncios").document(id).get()
.await()
return data.toObject(Anuncios::class.java)
and in my test I wrote like this:
#Test
fun `Get Add by id correct, should return data`() = runBlockingTest {
//GIVEN
coEvery {
firestore.collection("add").document("departament").collection("anuncios")
.document("01sm3zv3aCzGrWX3ycPT").get()
} returns dataTask
// WHEN
adRepository.getAnuncioId("01sm3zv3aCzGrWX3ycPT").apply {
// THEN
Truth.assertThat(this).isEqualTo(Anuncios())
coVerify(exactly = 1) {
firestore.collection("add").document("departament").collection("anuncios")
.document("01sm3zv3aCzGrWX3ycPT").get().await()
}
verify(exactly = 1) { datoSnap.toObject(Anuncios::class.java)!! }
}
}
the error throws me:
no answer found for: Task(#6).isComplete()
There is a problem with the await, but I don't know how to do it, I am new to unit test
Check out this and this, you can't run a test and wait for a real response, you have to mock it.
I solved it with:
mockkStatic("kotlinx.coroutines.tasks.TasksKt")
since this mocks the functions that are required
I am writing unit tests and I have this particular case when I change observable value before executing a suspend function and then right after. I would like to write a unit test to check if the value was changes twice correctly.
Here is the method:
fun doSomething() {
viewModelScope.launch(ioDispatcher) {
try {
viewModelScope.launch(Dispatchers.Main) {
commandLiveData.value = Pair(CANCEL_TIMER, null)
}
isProgress.set(true) //need to test it was set to true in one test
checkoutInteractor.doSomethingElse().run {
handleResult(this)
}
isProgress.set(false) //need to test it was set to false here in another test
} catch (ex: java.lang.Exception) {
handleHttpError(ex)
isProgress.set(false)
}
}
}
When writing a test I am calling doSomething() but I am unsure how to detect that the value was set to true before the checkoutInteractor.doSomethingElse call and set to false after.
Here is the test I have
#Test
fun `test doSomething enables progress`() {
runBlockingTest {
doReturn(Response()).`when`(checkoutInteractor). checkoutInteractor.doSomethingElse()
viewModel.doSomething()
assertTrue(viewModel.isProgress.get()) //fails obviously as the value was already set to false after the `doSomethingElse` was executed.
}
}
BTW, isProgress is an ObservableBoolean
You would need to either mock or spy on isProgress and checkoutInteractor fields to record and verify the execution of their methods.
Pass a mock or spy for isProcess and checkoutInteractor into your class.
Execute doSomething()
Verify inOrder the set() and doSomethingElse() functions
Example:
#Test
fun `test doSomething enables progress`() {
runBlockingTest {
val checkoutInteractor = Mockito.spy(CheckoutInteractor())
val isProcess = Mockito.spy(ObservableBoolean(true))
val viewModel = ViewModel(isProcess, checkoutInteractor)
viewModel.doSomething()
val inOrder = inOrder(isProcess, checkoutInteractor)
inOrder.verify(isProcess).set(true)
inOrder.verify(checkoutInteractor).doSomethingElse()
inOrder.verify(isProcess).set(false)
}
}
In Android, I was learning authentication in firebase. I want to store a Boolean value to a variable which is whether the task was successful or not. Here is my code:-
fun signIn(userEmail: String, userPassword: String): Boolean {
var successful = false
mAuth.signInWithEmailAndPassword(userEmail, userPassword)
.addOnCompleteListener {
successful = it.isSuccessful
Log.d(TAG, "successful = $successful")
}
Log.d(TAG, "successful = $successful")
return successful
}
When this method is invoked, the successful variable inside the higher-order function changes to true but it has no effect when it comes outside. Here is my log file:-
D/UserAuthentication: successful = true
D/UserAuthentication: successful = false
How do I fix this?
Your inner Log is called after your outer Log because the method signInWithEmailAndPassword is Asynchronous
Do something like this:
fun signIn(userEmail: String, userPassword: String, callback: (Task<AuthResult>) -> Unit) {
mAuth.signInWithEmailAndPassword(userEmail, userPassword)
.addOnCompleteListener {
callback.invoke(it)
}
}
Then call this function like this:
signIn("your_username", "your_password") {
if(it.isSuccessfull){
//Your login was successfull
}
}