Mock android Patterns with mockito

a 夏天 提交于 2019-12-23 20:00:25

问题


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.


回答1:


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);



            }


    }



回答2:


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




回答3:


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




回答4:


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.



来源:https://stackoverflow.com/questions/41518223/mock-android-patterns-with-mockito

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!