I'm trying to test a validity function. My function is like this:
class InvalidCredentialException(message: String) : Exception(message)
#Throws
fun credentialValidityChecker(email: String, password: String, nameAndFamily: String? = null) {
when {
email.isBlank() -> {
throw InvalidCredentialException("Email address can't left blank.")
}
!Patterns.EMAIL_ADDRESS.matcher(email)
.matches() -> {
throw InvalidCredentialException("Email address format is not correct.")
}
password.isBlank() -> {
throw InvalidCredentialException("Password can't left blank.")
}
password.length < 5 -> {
throw InvalidCredentialException("Password should have at least 5 characters.")
}
nameAndFamily != null -> {
if (nameAndFamily.isBlank())
throw InvalidCredentialException("Name and family can't left blank.")
}
}
}
I use this function to throw in case of any problem with the user credential. Otherwise, nothing happens, and the code continues. The exception is handled in other application layers.
and here are my test cases:
class CredentialValidityTest {
#Test
fun emptyEmail_raiseEmptyEmailException() {
try {
credentialValidityChecker(email = "", password = "12345")
fail("Empty email should raise exception.")
} catch (e: InvalidCredentialException) {
assertThat(e.message).isEqualTo("Email address can't left blank.")
}
}
#Test
fun wrongFormatEmail_raiseWrongEmailException() {
val wrongFormatEmailList = listOf(
"test", "test#", "test#application",
"test#application.", "test#.", "test.application#com"
)
for (email in wrongFormatEmailList)
try {
credentialValidityChecker(email = email, password = "12345")
fail("Wrong format email should raise exception.")
} catch (e: InvalidCredentialException) {
assertThat(e.message).isEqualTo("Email address format is not correct.")
}
}
#Test
fun emptyPassword_raiseEmptyPasswordException() {
try {
credentialValidityChecker(email = "test#application.com", password = "")
fail("Empty password should raise exception.")
} catch (e: InvalidCredentialException) {
assertThat(e.message).isEqualTo("Password can't left blank.")
}
}
#Test
fun weakPassword_raiseWeakPasswordException() {
try {
credentialValidityChecker(email = "test#application.com", password = "1234")
fail("weak password should raise exception.")
} catch (e: InvalidCredentialException) {
assertThat(e.message).isEqualTo("Password should have at least 5 characters.")
}
}
#Test
fun emptyNameAndFamily_raiseEmptyNameAndFamilyException() {
try {
credentialValidityChecker(
email = "test#application.com",
password = "12345",
nameAndFamily = ""
)
fail("Empty name and family should raise exception.")
} catch (e: InvalidCredentialException) {
assertThat(e.message).isEqualTo("Name and family can't left blank.")
}
}
}
The problem is:
Only the first test case pass, which checks email not be blank. The other test cases fail with the java.lang.NullPointerException error.
What is the problem?
Try using PatternsCompat.EMAIL_ADDRESS instead of Patterns.EMAIL_ADDRESS
Related
Here's a simple function that convert a string to currency format.
fun String.toCurrency(): String{
return try {
DecimalFormat("###,###").format(this.replace(",","").toInt())
} catch (E: NumberFormatException) {
this
}
}
And I want to test this method. So, I did
#Test(expected = NumberFormatException::class)
#Throws(NumberFormatException::class)
fun convertCurrency_returnAmericanFormat() {
val currentList = listOf("0", "1", "10", "100", "1000", "10000", "100000", "1000000", "100000000")
val expectedList = listOf("0", "1", "10", "100", "1,000", "10,000", "100,000", "1,000,000", "100,000,000")
currentList.forEachWithIndex { i, s ->
assertEquals(expectedList[i], s.toCurrency())
}
val exceptionList = listOf("!", "#")
exceptionList.forEach {
try {
it.toCurrency()
}catch (e: NumberFormatException){
assertEquals(NumberFormatException::class, e)
}
}
}
It didn't work and shows failure.
How can I pass the test case? I don't need to check the message but just ExceptionClass.
In toCurrency extension function, you are catching the number format exception and returning the original string. You should rethrow the exception or not to catch it at all.
// ...
catch(e: NumberFormatException) {
// log the exception or ...
throw e
}
Here, let's test only invalid scenario for toCurrency method. It would be easy to determine which test scenario failing or successing.
#Test
fun convertCurrency_invalidNumbers_throwsException() {
val invalidCurrencies = listOf("!", "#")
// check also for big numbers -> 999999999999
assertThrows<NumberFormatException> {
invalidCurrencies.forEach {
it.toCurrency()
}
}
}
#Test
#Throws(NumberFormatException::class)
fun convertCurrency_returnAmericanFormat() {
// test for successful toCurrency conversion
}
// writing junit ExerciseMainLogger class
so how to verify AnalyticsLog.insertEventLog(builder) using Mockito
I have mocked AnalyticsLog class but getting error Actually, there were zero interactions with this mock.
Wanted but not invoked
object ExerciseMainLogger {
fun setLog(eventName: String, screenId: String = "", dimension: Map<String, String> = mapOf()) {
LOG.d(TAG, "setLog - $eventName, $screenId, $dimension")
val builder = LogBuilders.EventBuilder()
.setEventName(eventName)
.setEventType(LogBuilders.EventType.NORMAL)
if (screenId.isNotEmpty()) {
builder.setScreenView(screenId)
}
if (dimension.isNotEmpty()) {
builder.setDimension(dimension)
}
AnalyticsLog.insertEventLog(builder)
}
}
AnalyticsLog Class
object AnalyticsLog {
#JvmStatic
fun insertEventLog(eventBuilder: EventBuilder) {
if (TestConfig.isTestMode()) {
LOG.d(TAG, "[SA] test mode")
return
}
try {
val eventLogs = eventBuilder.build()
val eventId = eventLogs[EVENT_ID_PROPERTY]
val result = insertLog(eventLogs)
if (FeatureManager.getInstance().getBooleanValue(FeatureList.Key.COMMON_DEVELOPER_MODE)) {
LOG.d(TAG, "[SA-DEV] insertEventLog: EventId: $eventId, logs: $eventLogs, send result: $result")
} else {
LOG.d(TAG, "[SA] insertEventLog: EventId: $eventId, send result: $result")
}
} catch (e: Exception) {
LOG.w(TAG, "[SA] insertEventLog exception, " + e.message)
e.printStackTrace()
}
}
}
My Test method looks like below. I trying to run the test case with the JUnit but getting error
mockkStatic(SamsungAnalyticsLog::class)
every { SamsungAnalyticsLog.insertEventLog(builder) } just runs
ExerciseMainLogger.setLog(
ExerciseMainLogger.EX2012,
screenId = screenId,
dimension = dimension
)
verify(exactly = 1) { AnalyticsLog.insertEventLog(builder) }
Verification failed: call 1 of 1: class com.samsung.android.wear.shealth.base.log.SamsungAnalyticsLog.insertEventLog(eq(com.samsung.context.sdk.samsunganalytics.LogBuilders$EventBuilder#71a04ac6))). Only one matching call to SamsungAnalyticsLog(static SamsungAnalyticsLog)/insertEventLog(EventBuilder) happened, but arguments are not matching:
[0]: argument: com.samsung.context.sdk.samsunganalytics.LogBuilders$EventBuilder#7b05129b, matcher: eq(com.samsung.context.sdk.samsunganalytics.LogBuilders$EventBuilder#71a04ac6), result: -
Stack trace:
I am trying to obtain phone number(s) in Jetpack compose following Googles Phone Number Hint Docs. But I am stuck in a problem where it says: getIntentSender() is unresolved in request: GetPhoneNumberHintIntentRequest.
I am also getting another error on addOnFailureListener
Type mismatch.
Required:
OnFailureListener
Found:
Int
#Composable
fun PhoneNumberConsent() {
val context = LocalContext.current
val request = GetPhoneNumberHintIntentRequest.builder().build()
val phoneNumberHintIntentResultLauncher = rememberLauncherForActivityResult(
contract = ActivityResultContracts.StartActivityForResult(),
) {
try {
val phoneNumber =
Identity.getSignInClient(context)
.getPhoneNumberFromIntent(it.data)
} catch (e: Exception) {
Log.e(TAG, "Phone Number Hint failed")
}
}
Identity.getSignInClient(context)
.getPhoneNumberHintIntent(request)
.addOnSuccessListener(
try {
phoneNumberHintIntentResultLauncher.launch(request.getIntentSender())
} catch (e: Exception) {
Log.e(TAG, "Launching the PendingIntent failed")
} as OnSuccessListener<in PendingIntent>
)
.addOnFailureListener(
Log.e(TAG, "Phone Number Hint failed")
)
}
addOnSuccessListener accepts a listener, which can be passed as trailing closure.
Result passed to this listener is a pending intent which has intentSender property, and it can be used to create IntentSenderRequest.
Here's a working example:
val context = LocalContext.current
val request = GetPhoneNumberHintIntentRequest.builder().build()
val phoneNumberHintIntentResultLauncher = rememberLauncherForActivityResult(
contract = ActivityResultContracts.StartIntentSenderForResult(),
) {
try {
val phoneNumber = Identity.getSignInClient(context)
.getPhoneNumberFromIntent(it.data)
println("phoneNumber $phoneNumber")
} catch (e: Exception) {
println("Phone Number Hint failed")
e.printStackTrace()
}
}
Button(onClick = {
Identity.getSignInClient(context)
.getPhoneNumberHintIntent(request)
.addOnSuccessListener { pendingIntent ->
try {
phoneNumberHintIntentResultLauncher.launch(
IntentSenderRequest.Builder(
pendingIntent.intentSender
).build()
)
} catch (e: Exception) {
println("Launching the PendingIntent failed")
e.printStackTrace()
}
}
.addOnFailureListener {
println("addOnFailureListener $it")
}
}) {
}
If you need to run it immediately after the view appears, use LaunchedEffect instead of Button.onClick. Your current approach contradicts one of the basic rules of Compose, which is that composable functions must be free of side-effects. Read more in thinking in compose
According to this docs there is no getIntentSender() method in GetPhoneNumberHintIntentRequest class. Maybe there is a typo in the tutorial you are following, try to use result instead of request:
Identity.getSignInClient(context)
.getPhoneNumberHintIntent(request)
.addOnSuccessListener { result ->
try {
phoneNumberHintIntentResultLauncher.launch(result.intentSender.sendIntent)
} catch (e: Exception) {
Log.e(TAG, "Launching the PendingIntent failed")
} as OnSuccessListener<in PendingIntent>
}
.addOnFailureListener(
Log.e(TAG, "Phone Number Hint failed")
)
viewModelScope.launch {
val req = RequestCodeMutation(phoneNumber)
val response = try {
ApolloClientManager
.apolloClient
.suspendMutate(req)
}
catch (e: ApolloException) {
println(e.message)
isError.value = true
null
}
finally {
loading.value = false
}
val requestCode = response?.data?.requestCode
println(response?.errors)
}
suspend fun <D : Operation.Data, T, V : Operation.Variables> ApolloClient.suspendMutate(mutation: Mutation<D, T, V>): Response<T> =
mutate(mutation).toDeferred().await()
This is my validator on server side. It is shown correctly on Graphiql, however, I am unable to receive this message on client side.
requestCode = async (resolve, source, args, context, info) => {
let { phoneNumber } = args;
phoneNumber = validator.trim(phoneNumber);
Object.assign(args, { phoneNumber });
if (!validator.isMobilePhone(phoneNumber)) {
throw new UserInputError('Invalid phone number provided!');
}
return resolve(source, args, context, info);
}
ApolloException.message is showing Internal Server Error and response?.errors is null.
response?.errors is not supposed to be null and show the proper error message that is being shown on GraphiQL.
In your catch block, you can build a new Response, based on the ApolloCall.
So consider the following:
import com.apollographql.apollo.api.Response
import com.apollographql.apollo.api.Error
fun <T> executeCall(call: ApolloCall<T>): Response<T> = try {
apolloCall.toDeferred().await()
} catch (apolloException: ApolloException) {
val error = Error(apolloException.message ?: "Unknown Error")
Response.builder(apolloCall.operation()).errors(listOf(error)).build()
}
Note: I assume that ApolloClientManager.apolloClient.suspendMutate(req) returns an instance of ApolloCall<T>.
You can then use this function like:
val call = ApolloClientManager.apolloClient.suspendMutate(RequestCodeMutation(phoneNumber))
val response = executeCall(call)
// check the response status code
following the code, in init function I create a Person object,and have an exception,now I want to stop the progress in catch like java return. How can I do it?
class Person {
val age: String = "10"
private lateinit var person: Person
init {
try {
person = get(2)
} catch (exception: Throwable) {
}
println("----------------do it $person.age")
}
fun get(i: Int): Person {
when (i) {
1 -> {
return Person()
}
else -> {
throw MyException("aaaaaaaaa")
}
}
}
}
If an instance cannot be created due to errors in init, this error shouldn't be suppressed but delegated to the caller. So just do not catch the exception and the init "stopps" automatically.