如何使用Mockito在android中模拟EditText



我正在尝试为我的android应用程序的验证器编写Unit Test。验证器接受参数EditText,因此我需要模拟它。但是,模拟不起作用,迫使Test在调用when()方法时崩溃,但有以下例外:

org.mockito.exceptions.misusing.MissingMethodInvocationException: 
when() requires an argument which has to be 'a method call on a mock'.
For example:
    when(mock.getArticles()).thenReturn(articles);
Also, this error might show up because:
1. you stub either of: final/private/equals()/hashCode() methods.
   Those methods *cannot* be stubbed/verified.
   Mocking methods declared on non-public parent classes is not supported.
2. inside when() you don't call method on mock but on some other object.

我的代码是:

@RunWith(MockitoJUnitRunner.class)
public class MyUnitTest
{
@Mock
Context mMockContext;
@Test
public void validateIsCorrect() {
     final EditText input = Mockito.mock(EditText.class);
     when(input.getText()).thenReturn(Editable.Factory.getInstance().newEditable("123"));
...
}
}

build.gradle文件中的依赖项包括:

 testCompile 'junit:junit:4.12'
 testCompile 'org.mockito:mockito-core:1.10.19'

EditText的方法getText()不是private也不是final。我做错了什么?可以这样嘲笑EditText吗?如何?

当你运行单元测试时,你使用的是标准的JVM上下文,而不是Android的上下文,这就是它崩溃的原因:Editable.Factory类及其方法(如getInstance())不在类路径中。他们也没有被嘲笑。我要做的是创建一个与private成员implements Editable的类来保存字符串引用并使用它来模拟getText()方法。像这样:

class MockEditable implements Editable {
    private String str;
    public MockEditable(String str) {
        this.str = str;
    }
    @Override @NonNull
    public String toString() {
        return str;
    }
    @Override
    public int length() {
        return str.length();
    }
    @Override
    public char charAt(int i) {
        return str.charAt(i);
    }
    @Override
    public CharSequence subSequence(int i, int i1) {
        return str.subSequence(i, i1);
    }
    @Override
    public Editable replace(int i, int i1, CharSequence charSequence, int i2, int i3) {
        return this;
    }
    @Override
    public Editable replace(int i, int i1, CharSequence charSequence) {
        return this;
    }
    @Override
    public Editable insert(int i, CharSequence charSequence, int i1, int i2) {
        return this;
    }
    @Override
    public Editable insert(int i, CharSequence charSequence) {
        return this;
    }
    @Override
    public Editable delete(int i, int i1) {
        return this;
    }
    @Override
    public Editable append(CharSequence charSequence) {
        return this;
    }
    @Override
    public Editable append(CharSequence charSequence, int i, int i1) {
        return this;
    }
    @Override
    public Editable append(char c) {
        return this;
    }
    @Override
    public void clear() {
    }
    @Override
    public void clearSpans() {
    }
    @Override
    public void setFilters(InputFilter[] inputFilters) {
    }
    @Override
    public InputFilter[] getFilters() {
        return new InputFilter[0];
    }
    @Override
    public void getChars(int i, int i1, char[] chars, int i2) {
    }
    @Override
    public void setSpan(Object o, int i, int i1, int i2) {
    }
    @Override
    public void removeSpan(Object o) {
    }
    @Override
    public <T> T[] getSpans(int i, int i1, Class<T> aClass) {
        return null;
    }
    @Override
    public int getSpanStart(Object o) {
        return 0;
    }
    @Override
    public int getSpanEnd(Object o) {
        return 0;
    }
    @Override
    public int getSpanFlags(Object o) {
        return 0;
    }
    @Override
    public int nextSpanTransition(int i, int i1, Class aClass) {
        return 0;
    }
}

然后,您可以使用此类

Mockito.when(input.getText()).thenReturn(new MockEditable("123"));

从更远的地方看这个;我在问自己:为什么你的验证者需要了解Android特定的类?

的意思是:我假设您的验证器(最终)必须检查字符串或类似内容的属性?

因此,我建议在这里集中精力分离关注点:

  1. 创建一个从编辑文本中获取字符串的组件
  2. 创建处理此类字符串的验证器

那么你首先不需要对你的验证者进行任何特定的模拟!

final EditText editText = Mockito.mock(EditText.class);
final ArgumentCaptor<Editable> captor = ArgumentCaptor.forClass(Editable.class);
Mockito.doNothing().when(editText).setText(captor.capture());
Mockito.when(editText.getText()).thenAnswer(new Answer<Object>() {
    @Override
    public Object answer(InvocationOnMock invocation) {
        return captor.getValue();
    }
});

这家伙呢,它对我有用:请不要忘记添加 MockitoAnnotations.init(this);并使用

@Mock private EditTextView passwordField;
 @Before
public void init() {
    MockitoAnnotations.initMocks(this);
    when(rootView.findViewById(R.id.button_logout)).thenReturn(buttonLogout);
    when(rootView.findViewById(R.id.button_unlock)).thenReturn(buttonUnlock);
    when(rootView.findViewById(R.id.ScreenLock_PasswordTextField)).thenReturn(passwordField);
    when(passwordField.getText()).thenReturn(Editable.Factory.getInstance().newEditable("asd"));
    when(application.getPassword()).thenReturn("asd");
    sut = new ScreenLockPresenterImpl(application, rootView, screenLockListener,
            logoutButtonClickListener);
}

@Test
public void testOnClickWhenOk() {
    sut.onClick(null);
    verify(passwordField).getText();
    verify(screenLockListener).unLock();
}

我认为这就是您要找的:when(passwordField.getText()).thenReturn(Editable.Factory.getInstance().newEditable("asd"));

相关内容

  • 没有找到相关文章