0

私が作成したいくつかの単体テストを改善しようとしているので、mockito を使用していくつかのオブジェクトをモックしています。今のところ、2 つの質問があります。AsyncTask をモックする必要がありますか?(もしそうなら)このモックされたオブジェクトを使用して、モックされたオブジェクトのdoInBackground()メソッドを呼び出すにはどうすればよいですか?

私はいくつかのことを試しましたが、まだ機能していません。私のテストではまだアサーションの失敗が返されます:

AsyncTask の実行方法 (StudioActivity.java 内):

.....

LocationTask task = new LocationTask();
task.execute((LocationManager) this.getSystemService(Context.LOCATION_SERVICE));

私の非同期タスク (StudioActivity.java 内):

.....

public class LocationTask extends AsyncTask<LocationManager, Void, String> {
    private LocationManager mLocationManager;

    // private TextView mLocText;

    @Override
    protected void onPreExecute() {
        super.onPreExecute();

        // mLocText = (TextView) findViewById(R.id.textView_location);
        // mLocText.setVisibility(View.VISIBLE);
    }

    @Override
    public String doInBackground(LocationManager... params) {
        mLocationManager = params[0];
        Location loc = mLocationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
        Geocoder gcd = new Geocoder(getApplicationContext(), Locale.getDefault());
        List<Address> addresses;
        try {
            addresses = gcd.getFromLocation(loc.getLatitude(), loc.getLongitude(), 1);
            if (addresses.size() > 0) {
                return (addresses.get(0).getLocality() + ", " + addresses.get(0).getCountryName());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    protected void onPostExecute(String result) {
        mPreviewFragment.setLocation(result);
        mLocation = result;
    }

}

これは私が試したものです。

私のテスト方法 (TestStudioActivity.java 内):

@UiThreadTest
public void testGeolocalistationLabel() throws InterruptedException, ExecutionException{
    LocationTask mockLocationTask = mock(StudioActivity.LocationTask.class);

    when(mockLocationTask.doInBackground((LocationManager[]) any())).thenReturn("JUnit, Location"); 

    mStudioBoastPreviewFragment.getGeoloc().performClick();       
    assertEquals("JUnit, Location",mStudioBoastPreviewFragment.getGeolocTextView().getText());

    verify(mockLocationTask).doInBackground((LocationManager[]) any());
}

また

@UiThreadTest
public void testGeolocalistationLabel() throws InterruptedException, ExecutionException{
    LocationTask mockLocationTask = mock(StudioActivity.LocationTask.class);

    when(mockLocationTask.doInBackground((LocationManager) mStudioActivity.getSystemService(Context.LOCATION_SERVICE))).thenReturn("JUnit, Location"); 

    mStudioBoastPreviewFragment.getGeoloc().performClick();       
    assertEquals("JUnit, Location",mStudioBoastPreviewFragment.getGeolocTextView().getText());

    verify(mockLocationTask).doInBackground((LocationManager) mStudioActivity.getSystemService(Context.LOCATION_SERVICE));
}

失敗:

junit.framework.AssertionFailedError: expected:<JUnit, Location> but was:<>
at  com.c4mprod.bhost.test.TestStudioActivity.testGeolocalistationLabel(TestStudioActivity.java:255)

モッキングなしで、それは機能しています。しかし、テストの実行には時間がかかります。そのため、テスト速度を向上させ、接続の問題やサーバー エラーを回避するために、Mockito を使用したいと考えました。場所がに表示されるかどうかをテストしたいだけですmStudioBoastPreviewFragment.getGeolocTextView()

どちらの場合もアサーションの失敗があるので、どの方法が最適で、それをどのように使用して this をモックできるかを知りたいと思いましたdoInBackground()。または、AsyncTask をモックする別の方法がある場合。

助けてくれてありがとう!

4

1 に答える 1

2

残念ながら、私は Android についてはあまり知りませんが、Mockito については少し知っています。

私が尋ねなければならない1つの質問は次のとおりです。

StudioBoastPreviewFragment は実際に LocationTask のインスタンスをどのように取得しますか? あなたのテストコードから推測できるのは、モックされた LocationTask が注入されていないことです.mStudioBoastPreviewFragmentはTestクラスのメンバーのようですが、mockLocationTaskはメソッドスコープ内で宣言およびインスタンス化されているため、あなたのmStudioBoastPreviewFragment は実際にモックを使用しています。

次に、モックの問題があります。

LocationTask が AsyncTask を継承していることがわかります。doInBackground(...) はどのように呼び出されますか? あなたはそれを呼び出していますか、それともこれは AsyncTask の内部ロジックによって呼び出されていますか (Thread.run() が Thread.start() によって呼び出されるのと同様)? Mockito は、ロジックを含まないダム プロキシ オブジェクトを作成することに注意してください。したがって、doInBackground(...) を呼び出す AsyncTask の内部ロジックに依存している場合、この内部ロジックはモックに存在しません。

つまり、これが単体テストの場合、最初に doInBackground(...) が呼び出されるかどうかは気にしません。これは、外部クライアント コードが AsyncTask または具体的なサブクラス LocationTask の内部に依存してはならないためです。Thread の例に戻ると、Thread.run() ではなく、Thread.start() をモック化します。

本当に単体テストが必要な場合は、2 つのクラスを別々にテストして、いずれかのクラスで潜在的なエラーを分離する必要があります。したがって、正しく行われれば、LocationTask をモックアウトすることをお勧めします。

一方、2 つのコンポーネント間の相互作用をテストしたい場合、これはもはや単体テストではなく、まったく別の話です。

于 2013-05-28T15:00:45.173 に答える