我开始围绕硬件特定功能编写一个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);
}
}
对此不太满意,因为我想在同一测试中测试不同的场景。
有什么想法吗?对此最好的方法是什么?
答案 0 :(得分:8)
这可以使用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);
}
}
我包含了导入功能,因此您可以看到它们的来源。 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();
}
}
您可以轻松传入要启用的功能的枚举或boolean
枚举,而不是已启用的Set
。确保禁用未明确启用的所有功能。在此示例中,如果您未将enabled
明确设置为true
,则它将为false
。
以下是注释本身的代码:
@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);
答案 1 :(得分: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
用法。基本上我会有策略类,它们在特定的硬件情况下会表现正常(类似于How to Replace (and not just move) Conditional Logic with Strategy?)。但这又取决于你的情况。如果仅使用这些条件的一两个地方,我就不会选择策略。
答案 2 :(得分:0)
@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));
}