2017-01-21 20 views
0

androidアプリケーションのバリデーターにUnit Testを書き込もうとしています。バリデーターはパラメータEditTextとして受け入れますので、私はそれを嘲笑する必要があります。しかしモックは例外でwhen()メソッドを呼び出すにクラッシュするTestを強制的に動作しません:Mockitoを使用してアンドロイドでEditTextをモックする方法

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' 

EditTextgetText()privateまたはではありません。私は間違って何をしていますか?このようにEditTextを模倣することは可能ですか?どうやって?

答えて

0

ユニットテストを実行しているときは、Androidのコンテキストではなく標準のJVMコンテキストを使用しているため、クラッシュしています。Editable.Factoryクラスとそのメソッド(getInstance()など)はクラスパスにありません。そして彼らはどちらも嘲笑されていません。 私は、文字列参照を保持し、getText()メソッドをモックするために使用するメンバを持つimplements Editableというクラスを作成することです。このような 何か:

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")); 
+0

'EditText'クラス自体がクラスパスにどのようになるのでしょうか? – Divers

+0

ユニットテストを実行するとアンドロイドが得られます。jarファイルをクラスパスに入れてテストを実行する必要があります。これは、 'EditText'クラスがそこにあるので、参照することができますが、メソッドの実装は空であり、使用時に実行時の例外がスローされるため、最初にそれらを使用するためにモックする必要があります。 – gcesarmza

+1

私はそれを取得しません。なぜあなた自身の編集可能なものを作成する必要がありますか、ちょうどそれも嘲笑できませんでしたか? – GhostCat

1

を利用することができます。私は自分自身に尋ねています:なぜあなたのバリデータはAndroid固有のクラスについて何か知る必要がありますか?

は、私が何を意味です:私は(最後に)あなたのバリデータは多分文字列、または同様の何かのプロパティをチェックしなければならないことを想定

私はこのように、ここでの懸念を分離するに集中することをお勧め:

  1. このような文字列

で動作するバリデータを作成し、あなたのEditText

  • から文字列をフェッチコンポーネントを作成します。それで、最初にバリデーターのための特定の嘲笑をする必要はありません!

  • +0

    私はパターンMVPを使用します。アクティビティーまたはフラグメントは、ビューを「ViewManager」に登録します。ビューアーは、検証も実行します。私は、EditTextから値を抽出し、文字列だけを受け入れるメソッドをテストすることができることを知っています。それにもかかわらず、Androidコンポーネントから隔離されていないテストを実行したいと思います。 – arjacsoh

    0

    この男はどうですか、それは私のために働きます: 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(); 
    } 
    

    を使用します。(。)Editable.Factory.getInstance()newEditable( "ASD") とき(passwordField.getText())thenReturn。

    関連する問題