Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can't mock android.util.Patterns.EMAIL_ADDRESS.pattern()

Currently I'm using MockK library (version 1.8.1) for unit tests in Android Dev, and I the problem is I can't mock Patterns.EMAIL_ADDRESS. Test cases throw NPE every time this property gets invoked.

I tried mockkStatic(Patterns::class), but @Before method crashes with NPE while applying the rule every { Patterns.EMAIL_ADDRESS.pattern() } returns EMAIL_REGEX_STRING.

Class I'm trying to test:

public class EmailValidator {

private static final String EMPTY = "";
private final Context context;

@Inject
public EmailValidator(Context context) {
    this.context = context;
}

public String isValidEmail(String email) {
    if (StringUtils.isEmpty(email)) {
        return context.getString(R.string.sign_up_error_email_empty);
    }

    if (!email.matches(Patterns.EMAIL_ADDRESS.pattern())) {
        return context.getString(R.string.sign_up_error_email_validate);
    }
    return EMPTY;
}}
like image 517
Vladislav Chetrari Avatar asked Jun 27 '18 09:06

Vladislav Chetrari


2 Answers

Try using

PatternsCompat.EMAIL_ADDRESS.pattern()

instead of just

Patterns.EMAIL_ADDRESS.pattern()

that did the job for me.

like image 152
Manuel Mariano Silva Avatar answered Nov 20 '22 17:11

Manuel Mariano Silva


Instead of using Patterns.EMAIL_ADDRESS directly, you could create a wrapper around it then mock or fake the wrapper.

The wrapper could be a method, like:

class EmailValidator {
    fun isValidEmail(email: String) {
        if (StringUtils.isEmpty(email)) {
            return context.getString(R.string.sign_up_error_email_empty);
        }

        if (!email.matches(getEmailPattern())) {
            return context.getString(R.string.sign_up_error_email_validate);
        }
    }

    private fun getEmailPattern(): String = Patterns.EMAIL_ADDRESS.pattern()
}

and your test could mock it like:

@Test
fun `test email validator`() {
    val validator = spyk(EmailValidator())

    every { validator["getEmailPattern"]() } returns yourTestPattern

    assertThat(validator.isValidEmail("blah blah blah")).isFalse()
}

Or create a class that wraps it, maybe a PatternFactory class

class PatternFactory {
    fun getEmailPattern(): String = ...
    fun getVinPattern(): String = ...
}

then pass in PatternFactory in as a dependency and mock it for the test

like image 36
Jamie Dulaney Avatar answered Nov 20 '22 15:11

Jamie Dulaney