5

I want validate an email with some code provided by Android.

Here is the code I want to mock :

 if(!Patterns.EMAIL_ADDRESS.matcher(email).matches())
      throw new InvalidPhoneException(phone);

In my test file :

@RunWith(PowerMockRunner.class)
@PrepareForTest({ Patterns.class })
public class UserTest {

    @Before
    public void mockValidator() {
        mockStatic(Patterns.class);
        when(Patterns.EMAIL_ADDRESS.matcher(any(String.class)).matches()).thenReturn(true);
    }

I got this error when I launch the tests :

java.lang.NullPointerException
    at ch.mycompany.myapp.model.UserTest.mockValidator(UserTest.java:59)

EDIT 1 :

I tried :

    mockStatic(Patterns.class);
    Field field = PowerMockito.field(Patterns.class, "EMAIL_ADDRESS");
    field.set(Patterns.class, mock(Pattern.class));

    // prepare matcher
    Matcher matcher = mock(Matcher.class);
    when(matcher.matches())
            .thenReturn(true);

    // final mock
    when(Patterns.EMAIL_ADDRESS.matcher(any(String.class)))
            .thenReturn(matcher);

But when I do that, my code (Patterns.EMAIL_ADDRESS.matcher(email).matches()) return always false. This is confusing.

Xero
  • 3,951
  • 4
  • 41
  • 73
  • Try to resolve it using Roboelectric. https://stackoverflow.com/questions/52638565/npe-on-unit-test-using-mockito?answertab=active#tab-top – Saku Nov 23 '19 at 00:54

4 Answers4

12

In this particular case it is not necessary to mock the Patterns class with mockito (it is unmockable anyways), just change your source code as follows:

 if(!Patterns.EMAIL_ADDRESS.matcher(email).matches())
  throw new InvalidPhoneException(phone);

should be

 if(!PatternsCompat.EMAIL_ADDRESS.matcher(email).matches())
  throw new InvalidPhoneException(phone);

That did the job for me.

Replace Patterns with PatternsCompat

from androidx.core.util.PatternsCompat

Salam El-Banna
  • 3,784
  • 1
  • 22
  • 34
  • 4
    It works, but I don't understand the difference between the two. Can you explain ? – Abel Jan 30 '20 at 14:10
  • This should be the selected answer , changing or using new libraries is not always possible , but this answer resolves the issue with minor change – yehyatt Aug 31 '21 at 12:32
3

you are performing the validation of the email field

you are not mocking the behaviour here when to return true or false. Also make a note we cannot mock final classes (Pattern).

when regex pattern matches with the value it returns true or false

Instead of complicating the things . Simply perform the valiation by passing the value.

Solution 1 :

     @Test
        public void test() throws Exception{            
            String email="hello@gmail.com";         
            System.out.println(Patterns.EMAIL_ADDRESS.matcher(email).matches());    

        }



 protected static class Patterns{


            private static final String EMAIL_PATTERN =
                    "^[_A-Za-z0-9-\\+]+(\\.[_A-Za-z0-9-]+)*@"
                    + "[A-Za-z0-9-]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})$";
            private static final Pattern EMAIL_ADDRESS=Pattern.compile(EMAIL_PATTERN);



        }
output :

true

Solution 2: Mocking the Matcher behaviour to return true or false

 @RunWith(PowerMockRunner.class)
    @PrepareForTest({Pattern.class,Matcher.class})
    public class TestEmailPattern {


            @Test
            public void test() throws Exception{            
                String email="hello@gmail.com";         
                Pattern pattern=PowerMockito.mock(Pattern.class);
                Matcher matcher=PowerMockito.mock(Matcher.class);
                PowerMockito.when(matcher.matches()).thenReturn(true);      
                assertEquals(Patterns.EMAIL_ADDRESS.matcher(email).matches(),true); 
            }

            protected static class Patterns{


                private static final String EMAIL_PATTERN =
                        "^[_A-Za-z0-9-\\+]+(\\.[_A-Za-z0-9-]+)*@"
                        + "[A-Za-z0-9-]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})$";
                private static final Pattern EMAIL_ADDRESS=Pattern.compile(EMAIL_PATTERN);



            }


    }
Barath
  • 5,093
  • 1
  • 17
  • 42
2

Using Robolectric will save you lot of headaches in this kind of situation.

Naren
  • 2,706
  • 1
  • 21
  • 15
  • Using Robolectric removed the NPE great!! But it did so in only my personal project but in my work codebase, it still produced NPE even after following the same steps. Is there anything you could think of which could have caused this – Yaswant Narayan May 30 '19 at 10:46
0

You can mock final classes with Mockito 2 https://github.com/mockito/mockito/wiki/What's-new-in-Mockito-2#mock-the-unmockable-opt-in-mocking-of-final-classesmethods

SpyZip
  • 5,511
  • 4
  • 32
  • 53