如何在Android上使用Robolectric测试特定的硬件功能?

Tos*_*osa 5 java testing android robolectric

我开始围绕硬件特定功能编写一个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;
    }
}
Run Code Online (Sandbox Code Playgroud)

所以我想测试不同的场景,那里有前置摄像头和后置摄像头,只有前置摄像头或根本没有摄像头.在我的应用程序中它有点复杂,但希望这使我更容易理解我的意思.

现在我这样做了,感觉有点奇怪.

RobolectricPackageManager pm = (RobolectricPackageManager) Robolectric.application.getPackageManager();
pm.setSystemFeature(PackageManager.FEATURE_CAMERA, true);
Run Code Online (Sandbox Code Playgroud)

我想过编写自己的测试运行器,所以对于所有预期的硬件设置,这样的特定运行器

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);
  }
}
Run Code Online (Sandbox Code Playgroud)

对此不太满意,因为我想在同一测试中测试不同的场景.

有任何想法吗?这是最好的方法吗?

Joe*_*Joe 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);
    }

}
Run Code Online (Sandbox Code Playgroud)

这是规则:

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);
    }

}
Run Code Online (Sandbox Code Playgroud)

我包括了进口,所以你可以从它们的起源位置看到.Statement是只有一个函数的接口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();
    }

}
Run Code Online (Sandbox Code Playgroud)

而不是启用的boolean,你可以很容易地通过在枚举或Set枚举你要启用哪些功能.确保禁用未明确启用的所有功能.在这个例子中,如果你不明确设置enabledtrue这将是false.

以下是注释本身的代码:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface EnableCamera {
}
Run Code Online (Sandbox Code Playgroud)

@EnableCamera除此之外,这将允许您使用它来注释该函数@Test.如果要为同一测试启用多个功能,可以在该功能上添加多个注释.

为了完整起见,这里是CameraHolder的实现(但你不需要这个):

public class CameraHolder {
    public static boolean CAMERA = false;
}
Run Code Online (Sandbox Code Playgroud)

我尝试使用robolectric,但我的版本的robolectric没有你使用的功能:

RobolectricPackageManager pm = (RobolectricPackageManager) Robolectric.application.getPackageManager();
// My version of robolectric didn't have this function.
pm.setSystemFeature(PackageManager.FEATURE_CAMERA, true);
Run Code Online (Sandbox Code Playgroud)

  • 谢谢.我能够用junit 4.8.2重新编译我的答案并且它有效.看起来好像4.8.2具有所有适当的类.http://grepcode.com/snapshot/repo1.maven.org/maven2/junit/junit/4.8.2我更新了我的答案. (3认同)