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为.truefalse

这是注释本身的代码:

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

这将允许您使用它来注释函数,@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(). 此类将需要四次测试——针对每种相机存在情况。所有这些都需要您使用Robolectric进行操作。

对于做实际工作的类,我将模拟 HardwareInfo 并有一种设置方法:

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

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

    return info;
}

您可以使用JUnit规则将其自动化/编写更少的代码作为上面/下面的答案。

也许我会走得更远,我不确定它是否适合您的情况。HardwareInfo我会直接在课堂上摆脱使用。基本上我会有在特定硬件情况下正确运行的策略类(类似于如何用策略替换(而不仅仅是移动)条件逻辑?)。但这又取决于您的情况。如果只有一两个地方使用这些条件,我不会采用策略。

于 2013-02-15T06:42:44.943 回答
1
@Test
public void hasCamera(){
    MainActivity activity = Robolectric.buildActivity( MainActivity.class )
            .create()
            .resume()
            .get();

    PackageManager packageManager = activity.getApplication().getPackageManager();
    ShadowPackageManager shadowPackageManager = shadowOf(packageManager);

    shadowPackageManager.setSystemFeature(PackageManager.FEATURE_CAMERA, true);
    assert(CameraUtils.checkCameraHardware(activity));

    shadowPackageManager.setSystemFeature(PackageManager.FEATURE_CAMERA, false);
    assert(!CameraUtils.checkCameraHardware(activity));

}
于 2019-01-30T17:39:14.300 回答