サーチ…


備考

ローカルユニットテストの作成

テストクラスは/src/test/<pkg_name>/

テストクラスの例

public class ExampleUnitTest {
    @Test
    public void addition_isCorrect() throws Exception {
        int a=4, b=5, c;
        c = a + b;
        assertEquals(9, c); // This test passes
        assertEquals(10, c); //Test fails
    }
}

壊す

public class ExampleUnitTest {
  ...
}

テストクラスでは、いくつかのテストクラスを作成し、それらをテストパッケージ内に配置することができます。

@Test
public void addition_isCorrect() {
   ...
}

テストメソッド、いくつかのテストメソッドは、テストクラス内で作成することができます。

注釈@Test注目してください。

Testアノテーションは、JUnitに、それが接続されているpublic voidメソッドをテストケースとして実行できることをJUnitに伝えます。

@Before@Afterなどの便利なアノテーションがいくつかあります。 このページは、開始するのに適しています。

assertEquals(9, c); // This test passes
assertEquals(10, c); //Test fails

これらのメソッドは、 Assertクラスのメンバです。いくつかの他の有用な方法であるassertFalse() assertNotNull() assertTrueなどはここで精巧だ説明


JUnitテストのアノテーション情報:

@Test: TestアノテーションはJUnitに、それが接続されているpublic voidメソッドをテストケースとして実行できることをJUnitに伝えます。メソッドを実行するために、JUnitは最初にクラスの新しいインスタンスを構築し、注釈付きメソッドを呼び出します。

@Before:テストを書くとき、いくつかのテストが実行される前に作成された同様のオブジェクトを必要とすることが一般的です。 @Before public voidメソッドに注釈を@Beforeと、そのメソッドはTestメソッドの前に実行されます。

@After: Beforeメソッドで外部リソースを割り当てる場合は、テストの実行後に外部リソースを解放する必要があります。 @After public voidメソッドに注釈を@Afterと、そのメソッドはTestメソッドの後に実行されます。 @AfterメソッドまたはTestメソッドが例外をスローした場合でも、すべての@Afterメソッドが実行されることが保証されています。


ヒント簡単にAndroid Studioでテストクラスを作成する

  • テストクラスを作成するクラス名の上にカーソルを置きます。
  • Alt + Enter(Windows)を押します。
  • Create Testを選択し、Returnを押します。
  • テストメソッドを作成するメソッドを選択し、[OK]をクリックします。
  • テストクラスを作成するディレクトリを選択します。
  • あなたは完了です、これはあなたの最初のテストです。

ヒント簡単にAndroid Studioでテストを実行する

  • パッケージを右クリックしてテストします。
  • 実行テストを選択してください...
  • パッケージ内のすべてのテストが一度に実行されます。

Androidコンポネックスからビジネスロジックへの移行

ローカルJVM単体テストの多くの価値は、アプリケーションの設計方法にあります。 Androidコンポーネントからビジネスロジックを切り離すことができるような方法で設計する必要があります。ここでは、 Model-View-Presenterパターンを使用した方法の例を示します 。これを実践するには、ユーザー名とパスワードのみを使用する基本的なサインアップ画面を実装します。私たちのAndroidアプリは、ユーザが提供するユーザ名が空ではなく、パスワードが少なくとも8桁で少なくとも1桁の数字であることを確認する責任があります。ユーザー名/パスワードが有効な場合は、サインアップAPIコールを実行します。それ以外の場合は、エラーメッセージが表示されます。

ビジネスロジックがAndroidコンポーネントと高度に結合されている例。

public class LoginActivity extends Activity{
    ...
    private void onSubmitButtonClicked(){
        String username = findViewById(R.id.username).getText().toString();
        String password = findViewById(R.id.password).getText().toString();
        boolean isUsernameValid = username != null && username.trim().length() != 0;
        boolean isPasswordValid = password != null && password.trim().length() >= 8 && password.matches(".*\\d+.*");
        if(isUsernameValid && isPasswordValid){
            performSignUpApiCall(username, password);
        } else {
            displayInvalidCredentialsErrorMessage();
        }
    }
}

ビジネスロジックがAndroidコンポーネントから切り離されている例。

ここでは、さまざまなクラス間のさまざまな相互作用を格納する単一のクラスLoginContractを定義します。

public interface LoginContract {
    public interface View {
        performSignUpApiCall(String username, String password);
        displayInvalidCredentialsErrorMessage();
    }
    public interface Presenter {
        void validateUserCredentials(String username, String password);
    }
}

私たちのLoginActivityは、ユーザーのサインアップフォーム(ビジネスロジック)の検証方法を知らなくてはならないという点を除いて、ほとんど同じです。 LoginActivityは、新しいLoginPresenterを使用して検証を実行します。

public class LoginActivity extends Activity implements LoginContract.View{
    private LoginContract.Presenter presenter;

    protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            presenter = new LoginPresenter(this);
            ....
        }
        ...

        private void onSubmitButtonClicked(){
            String username = findViewById(R.id.username).getText().toString();
            String password = findViewById(R.id.password).getText().toString();
            presenter.validateUserCredentials(username, password);
    }
    ...
}

ビジネスロジックは新しいLoginPresenterクラスに存在します。

public class LoginPresenter implements LoginContract.Presenter{
    private LoginContract.View view;

    public LoginPresenter(LoginContract.View view){
        this.view = view;
    }

    public void validateUserCredentials(String username, String password){
        boolean isUsernameValid = username != null && username.trim().length() != 0;
        boolean isPasswordValid = password != null && password.trim().length() >= 8 && password.matches(".*\\d+.*");
        if(isUsernameValid && isPasswordValid){
            view.performSignUpApiCall(username, password);
        } else {
            view.displayInvalidCredentialsErrorMessage();
        }
    }
}

これで、新しいLoginPresenterクラスに対してローカルJVMユニットテストを作成できます。

public class LoginPresenterTest {

    @Mock
    LoginContract.View view;

    private LoginPresenter presenter;

    @Before
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);
        presenter = new LoginPresenter(view);
    }

    @Test
    public void test_validateUserCredentials_userDidNotEnterUsername_displayErrorMessage() throws Exception {
        String username = "";
        String password = "kingslayer1";
        presenter.validateUserCredentials(username, password);
        Mockito.verify(view). displayInvalidCredentialsErrorMessage();
    }

    @Test
    public void test_validateUserCredentials_userEnteredFourLettersAndOneDigitPassword_displayErrorMessage() throws Exception {
        String username = "Jaime Lanninster";
        String password = "king1";
        presenter.validateUserCredentials(username, password);
        Mockito.verify(view). displayInvalidCredentialsErrorMessage();
    }

    @Test
    public void test_validateUserCredentials_userEnteredNineLettersButNoDigitsPassword_displayErrorMessage() throws Exception {
        String username = "Jaime Lanninster";
        String password = "kingslayer";
        presenter.validateUserCredentials(username, password);
        Mockito.verify(view). displayInvalidCredentialsErrorMessage();
    }

    @Test
    public void test_validateUserCredentials_userEnteredNineLettersButOneDigitPassword_performApiCallToSignUpUser() throws Exception {
        String username = "Jaime Lanninster";
        String password = "kingslayer1";
        presenter.validateUserCredentials(username, password);
        Mockito.verify(view).performSignUpApiCall(username, password);
    }
}

ご覧のように、LoginActivityからビジネスロジックを抽出し、それをLoginPresenter POJOに配置したとき。ビジネスロジックに対してローカルJVM単体テストを作成できるようになりました。

私たちが1つの責任を持つクラスごとに遵守すること、クラスを追加することなど、アーキテクチャーの変更には他にもさまざまな意味があることに注意してください。これは私がこれを実行する方法の副作用ですMVPスタイルによるデカップリング。 MVPはこの問題を解決する方法の1つに過ぎませんが、 MVVMのような他の選択肢があります。あなたはあなたのために働く最高のシステムを選ぶだけです。

JUnitを使い始める

セットアップ

JUnitを使用してAndroidプロジェクトのユニットテストを開始するには、プロジェクトにJUnit依存関係を追加する必要があります。ユニットテストのソースコードを含むテストソースセットを作成する必要があります。 Android Studioで作成されたプロジェクトには、すでにJUnitの依存関係とテストソースセットが含まれていることがよくあります

あなたのモジュールに次の行を追加しますbuild.gradle依存関係内のファイルClosure

testCompile 'junit:junit:4.12'

JUnitテストクラスは、 testという名前の特別なソースセットにありtest 。このソースセットが存在しない場合は、自分で新しいフォルダを作成する必要があります。デフォルトのAndroid Studio(Gradleベース)プロジェクトのフォルダ構造は次のようになります。

<project-root-folder>
    /app (module root folder)
        /build
        /libs
        /src
            /main (source code)
            /test (unit test source code)
            /androidTest (instrumentation test source code)
        build.gradle (module gradle file)
    /build
    /gradle
    build.gradle (project gradle file)
    gradle.properties
    gradlew
    gradlew.bat
    local.properties
    settings.gradle (gradle settings)

プロジェクトに/app/src/testフォルダがない場合は、自分で作成する必要があります。 testフォルダ内には、 javaフォルダも必要です(存在しない場合は作成してください)。 testソースセット内のjavaフォルダには、 mainソースセットと同じパッケージ構造が含まれている必要があります。

正しく設定した場合(Android StudioのAndroidビューで)、プロジェクトの構造は次のようになります。

プロジェクトセットアップ

注: androidTestソースセットを必ずしも持つ必要はありませんが、このソースセットはAndroidスタジオで作成されたプロジェクトで見つかることが多く、参照用にここに含まれています。


テストの作成

  1. testソースセット内に新しいクラスを作成します。
    プロジェクトビューでテストソースセットを右クリックし、 New > Java class選択します。
    最もよく使用される命名パターンは、 Test追加するテストのクラス名を使用することです。だから、 StringUtilitiesなりStringUtilitiesTest

  2. @RunWithアノテーションを追加する
    @RunWithアノテーションは、テストクラスで定義するテストをJUnitに実行させるために必要です。デフォルトのJUnitランナー(JUnit 4用)はBlockJUnit4ClassRunnerが、これを直接実行する代わりに、デフォルトのJUnitランナーの短縮形である別名JUnit4を使用する方が便利です。

     @RunWith(JUnit4.class)
     public class StringUtilitiesTest {
     
     }
    
  3. テストを作成する
    単体テストは、基本的に単なるテストであり、ほとんどの場合、実行すると失敗しないはずです。言い換えれば、例外をスローするべきではありません。テストメソッドの中では、ほとんどの場合、特定の条件が満たされているかどうかを確認するアサーションがあります。アサーションが失敗した場合、それはメソッド/テストを失敗させる例外をスローします。テストメソッドは常に@Testアノテーションでアノテートされます。この注釈がないと、JUnitは自動的にテストを実行しません。

     @RunWith(JUnit4.class)
     public class StringUtilitiesTest {
    
         @Test
         public void addition_isCorrect() throws Exception {
             assertEquals("Hello JUnit", "Hello" + " " + "JUnit");
         }
     }
    

    注:標準のJavaメソッドの命名規則とは異なり、テストメソッド名にはアンダースコアが含まれることがよくあります。


テストの実行

  1. 方法
    単一のテストメソッドを実行するには、メソッドを右クリックし、 Run 'addition_isCorrect()'か、キーボードショートカットctrl+shift+f10ます。 単一の単体テストを実行する

    すべてが正しく設定されていれば、JUnitはメソッドの実行を開始し、Android Studio内に次のインターフェースが表示されます。

    Androidスタジオユニットテストインターフェイス

  1. クラス
    プロジェクトビューでクラスを右クリックし、 Run 'StringUtilitiesTest 'をクリックするか、プロジェクトビューでクラスを選択した場合はキーボードショートカットctrl+shift+f10使用して、単一のクラスで定義されたすべてのテストを実行することもできます。

  2. パッケージ(すべて)
    プロジェクト内またはパッケージ内で定義されたすべてのテストを実行したくない場合は、単一のクラスで定義されたすべてのテストを実行するのと同じように、パッケージを右クリックして[ Run ... ]をクリックしRun ...

例外

JUnitは、メソッドが特定の入力に対して特定の例外をスローするかどうかをテストするためにも使用できます。

この例では、ブール形式(入力)が認識されないか不明な場合、次のメソッドが実際に例外をスローするかどうかをテストします。

public static boolean parseBoolean(@NonNull String raw) throws IllegalArgumentException{
    raw = raw.toLowerCase().trim();
    switch (raw) {
        case "t": case "yes": case "1": case "true":
            return true;
        case "f": case "no": case "0": case "false":
            return false;
        default:
            throw new IllegalArgumentException("Unknown boolean format: " + raw);
    }
}

@Testアノテーションにexpectedパラメータを追加することによって、スローされると予想される例外を定義することができます。この例外が発生しない場合、ユニットテストは失敗し、例外が実際にスローされた場合は成功します。

@Test(expected = IllegalArgumentException.class)
public void parseBoolean_parsesInvalidFormat_throwsException(){
    StringUtilities.parseBoolean("Hello JUnit");
}

これはうまくいきますが、メソッド内のテストケースが1つに制限されます。 1つの方法で複数のケースをテストしたい場合があります。この制限を克服するためによく使用される手法は、 try-catchブロックとAssert.fail()メソッドを使用することです。

@Test
public void parseBoolean_parsesInvalidFormats_throwsException(){
    try {
        StringUtilities.parseBoolean("Hello!");
        fail("Expected IllegalArgumentException");
    } catch(IllegalArgumentException e){
    }

    try {
        StringUtilities.parseBoolean("JUnit!");
        fail("Expected IllegalArgumentException");
    } catch(IllegalArgumentException e){
    }
}

注:ユニットテストの中で1つ以上のケースをテストすることは悪い習慣と考える人もいます。

静的インポート

JUnitは、各プリミティブ型に対して少なくとも1つのかなりのassertEqualsメソッドを定義し、Objectsに対して1つのメソッドを定義しています。これらのメソッドは、デフォルトでは直接呼び出すことができず、 Assert.assertEqualsように呼び出す必要があります。しかし、これらのメソッドは非常に頻繁に使用されるため、メソッドは静的なインポートを使用するため、メソッドがクラスの一部であるかのように直接使用できます。

assertEqualsメソッドの静的インポートを追加するには、次のimport文を使用します。

import static org.junit.Assert.assertEquals;

次の静的インポートを使用して、 assertArrayEqualsassertNotNull 、およびassertFalseなどのすべてのアサートメソッドを静的にインポートすることもできます。

import static org.junit.Assert.*;

静的インポートを使用しない場合:

@Test
public void addition_isCorrect(){
    Assert.assertEquals(4 , 2 + 2);
}

静的インポートの場合:

@Test
public void addition_isCorrect(){
    assertEquals(4 , 2 + 2);
}


Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow