I\'m trying to implement some unit tests for a couple of classes that rely on WifiManager and the returned ScanResults. What I\'d like to do is be able to control the ScanR
I've been struggling for a while to build ScanResult
object. I have successfully used that reflection approach above.
If somebody is searching for a way to clone ScanResult
object (or any other object implementing Parcelable
interface) you can use this approach (I checked it right in a unit test):
@RunWith(RobolectricTestRunner.class)
@Config(manifest=Config.NONE)
public class MovingAverageQueueTests {
@Test
public void parcelTest() {
Parcel parcel = Parcel.obtain();
ScanResult sr = buildScanResult("01:02:03:04:05:06", 70);
parcel.writeValue(sr);
parcel.setDataPosition(0); // required after unmarshalling
ScanResult clone = (ScanResult)parcel.readValue(ScanResult.class.getClassLoader());
parcel.recycle();
assertThat(clone.BSSID, is(equalTo(sr.BSSID)));
assertThat(clone.level, is(equalTo(sr.level)));
assertThat(clone, is(not(sameInstance(sr))));
}
private ScanResult buildScanResult(String mac, int level) {
Constructor ctor = null;
ScanResult sr = null;
try {
ctor = ScanResult.class.getDeclaredConstructor(null);
ctor.setAccessible(true);
sr = ctor.newInstance(null);
sr.BSSID = mac;
sr.level = level;
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return sr;
}
}
And as for performance, this naive check:
@Test
public void buildVsClonePerformanceTest() {
ScanResult sr = null;
long start = System.nanoTime();
for (int i = 0; i < 1000000; i++) {
sr = buildScanResult("01:02:03:04:05:06", 70);
}
long elapsedNanos = System.nanoTime() - start;
LOGGER.info("buildScanResult: " + elapsedNanos);
start = System.nanoTime();
for (int i = 0; i < 1000000; i++) {
sr = cloneScanResult(sr);
}
elapsedNanos = System.nanoTime() - start;
LOGGER.info("cloneScanResult: " + elapsedNanos);
}
Showed these results:
Oct 26, 2016 3:25:19 PM com.example.neutrino.maze.MovingAverageQueueTests buildVsClonePerformanceTest INFO: buildScanResult: 202072179 Oct 26, 2016 3:25:21 PM com.example.neutrino.maze.MovingAverageQueueTests buildVsClonePerformanceTest INFO: cloneScanResult: 2004391903
So cloning this way is 10 times less effective than creating instance even with reflection. I know this test is not robust as optimizations are done while compiling... However factor of ten is difficult to mitigate. I did also tested 10K iterations and then the factor was even 100! Just for your information.
P.S. getting Parcel.obtain() and parcel.recycle out of loop doesn't help