I started writing a robolectric test around hardware specific features, like sensors and camera (front and back).
Imagine this class:
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;
}
}
So i want to test different scenarios where there is a front camera and a rear camera, only a front camera or no camera at all. In my app its a bit more complicated but hope this makes it easier to understand what i mean.
For now i did it like this, which feels a bit odd.
RobolectricPackageManager pm = (RobolectricPackageManager) Robolectric.application.getPackageManager();
pm.setSystemFeature(PackageManager.FEATURE_CAMERA, true);
I thought about writing my own test runner, so for all expected hardware settings a specific runner like this
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);
}
}
Not quite happy with that either as i want to test different scenarios in the same test.
Any ideas? Whats the best approach for this?
This can be done with JUnit rules. I wrote this example while using JUnit 4.8.2.
Here is the test class:
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);
}
}
Here is the rule:
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);
}
}
I included the imports so you can see from where they originated. Statement is an interface with only a function evaluate()
.
Here is the statement class:
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();
}
}
Instead of an enabled boolean
you can easily pass in an enumeration or a Set
of enumerations for which features you want enabled. Make sure to disable all features that are not explicitly enabled. In this example, if you don't explicitly set enabled
to true
it will be false
.
Here is the code for the annotation itself:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface EnableCamera {
}
This would allow you to use this to annotate the function with @EnableCamera
in addition to @Test
. If you want to have multiple features on for the same test you can put multiple annotations on the function.
For the sake of completeness here is the implementation of CameraHolder (but you won't need this):
public class CameraHolder {
public static boolean CAMERA = false;
}
I tried with robolectric, but my version of robolectric didn't have the function you were using:
RobolectricPackageManager pm = (RobolectricPackageManager) Robolectric.application.getPackageManager();
// My version of robolectric didn't have this function.
pm.setSystemFeature(PackageManager.FEATURE_CAMERA, true);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With