5

センサーやカメラ (前面と背面) などのハードウェア固有の機能に関する robolectric テストの作成を開始しました。

このクラスを想像してください:

class CheckHardware {

    private bolean hasCamera(Context context) {
        PackageManager pm = context.callingActivityContext
            .getPackageManager();
        // camera support
        Boolean frontCam = pm.hasSystemFeature("android.hardware.camera.front");
        Boolean rearCam = pm.hasSystemFeature(PackageManager.FEATURE_CAMERA);
        if (frontCam || rearCam) {
            return true;
        }
        return false;
    }
}

そのため、フロント カメラとリア カメラがある場合、フロント カメラのみがある場合、またはカメラがまったくない場合のさまざまなシナリオをテストしたいと考えています。私のアプリではもう少し複雑ですが、これで私の言いたいことが理解しやすくなることを願っています。

今のところ、私はこのようにしましたが、少し奇妙に感じます。

RobolectricPackageManager pm = (RobolectricPackageManager) Robolectric.application.getPackageManager();
pm.setSystemFeature(PackageManager.FEATURE_CAMERA, true);

独自のテスト ランナーを作成することを考えたので、予想されるすべてのハードウェア設定に対して、このような特定のランナー

public class WithCameraTestRunner extends RobolectricTestRunner {   
  @Override
  public void setupApplicationstate(RobolectricConfig robolectricConfig) {
    super.setupApplicationState(robolectricConfig);
    ShadowApplication shadowApplication = shadowOf(Robolectric.application);
    shadowApplication.setPackageName(robolectricConfig.getPackageName());
    RobolectricPackageManager pm = new RobolectricPackageManager(Robolectric.application, robolectricConfig)
    pm.setSystemFeature(PackageManager.FEATURE_CAMERA, true);
    shadowApplication.setPackageManager(pm);
  }
}

同じテストでさまざまなシナリオをテストしたいので、それにはあまり満足していません。

何か案は?これに対する最善のアプローチは何ですか?

4

3 に答える 3

9

これは、JUnit ルールで実行できます。この例は、JUnit 4.8.2 を使用して書きました。

テストクラスは次のとおりです。

public class CameraTest {

    @Rule
    public CameraRule rule = new CameraRule();

    @Test
    @EnableCamera
    public void testWithCamera() {
        Assert.assertTrue(CameraHolder.CAMERA);
    }

    @Test
    public void testWithoutCamera() {
        Assert.assertFalse(CameraHolder.CAMERA);
    }

}

ルールは次のとおりです。

import org.junit.rules.MethodRule;
import org.junit.runners.model.FrameworkMethod;
import org.junit.runners.model.Statement;

public class CameraRule implements MethodRule {

    @Override
    public Statement apply(Statement base, FrameworkMethod method, Object target) {
        boolean camera = false;
        if (method.getAnnotation(EnableCamera.class) != null) {
            camera = true;
        }

        return new CameraStatement(camera, base);
    }

}

輸入元を確認できるように、輸入品を含めました。ステートメントは、関数のみを持つインターフェイスevaluate()です。

ステートメントクラスは次のとおりです。

import org.junit.runners.model.Statement;

public class CameraStatement extends Statement {

    private boolean mEnabled;
    private Statement mStatement;

    public CameraStatement(boolean enabled, Statement statement) {
        mEnabled = enabled;
        mStatement = statement;
    }

    @Override
    public void evaluate() throws Throwable {
        CameraHolder.CAMERA = mEnabled;
        mStatement.evaluate();
    }

}

有効にする代わりに、有効にする機能のboolean列挙または列挙の を簡単に渡すことができますSet。明示的に有効になっていないすべての機能を必ず無効にしてください。この例では、明示的に設定enabledしないtrueと になりますfalse

注釈自体のコードは次のとおりです。

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface EnableCamera {
}

これにより、 this を使用して@EnableCamera、 に加えて関数に注釈を付けることができます@Test。同じテストで複数の機能を使用したい場合は、関数に複数の注釈を付けることができます。

完全を期すために、ここに CameraHolder の実装を示します (ただし、これは必要ありません)。

public class CameraHolder {
    public static boolean CAMERA = false;
}

私は robolectric で試しましたが、私のバージョンの robolectric にはあなたが使用していた機能がありませんでした:

RobolectricPackageManager pm = (RobolectricPackageManager) Robolectric.application.getPackageManager();
// My version of robolectric didn't have this function.
pm.setSystemFeature(PackageManager.FEATURE_CAMERA, true);
于 2013-02-15T05:49:49.370 に答える
2

おそらくHardwareInfo、メソッドhasBackCamera()hasFrontCamera(). このクラスでは、カメラの存在のケースごとに 4 つのテストが必要です。そして、それらはすべてRobolectricで操作する必要があります。

実際の仕事をしているクラスについては、HardwareInfo をモックして、一種のセットアップ メソッドを用意します。

HardwareInfo infoWithFromCameraAndBackCamera() {
    HardwareInfo info = mock( HardwareInfo.class );

    when( info.hasBackCamera() ).thenReturn( true );
    when( info.hasFrontCamera() ).thenReturn( true );

    return info;
}

JUnitルールを使用して、上記/以下の回答として自動化/少ないコードを書くことができます。

あなたのケースに適しているかどうかはわかりませんが、さらに先に進むかもしれません。HardwareInfo私はクラスで直接使用を取り除きます。基本的に、特定のハードウェアのケースで正しく動作する戦略クラスがあります(How to Replace (and not just move) Conditional Logic with Strategy? に似ています)。しかし、それはあなたの状況によって異なります。これらの条件が使用される場所が 1 つまたは 2 つだけである場合、私は戦略を使用しません。

于 2013-02-15T06:42:44.943 に答える