Mocking up WifiManager for Android Unit Testing

前端 未结 3 953
时光说笑
时光说笑 2021-01-13 08:30

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

3条回答
  •  粉色の甜心
    2021-01-13 09:16

    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

提交回复
热议问题