【问题标题】:Unit Testing a BroadcastReceiver单元测试广播接收器
【发布时间】:2017-05-31 02:19:01
【问题描述】:

我一直在尝试弄清楚如何对我的 BroadcastReceiver 进行单元测试,并且我查看了 StackOverflow 和其他网站,但找不到解决问题的方法。

在我的 mainActivity 中,我有以下两个功能:

private void registerNetRcvr(){

    if (!isRcvrRegistered) {        
        isRcvrRegistered = true;
        registerReceiver(receiver, new IntentFilter("android.net.wifi.STATE_CHANGE"));
        registerReceiver(receiver, new IntentFilter("android.net.conn.CONNECTIVITY_CHANGE"));
    }
}

private BroadcastReceiver receiver = new BroadcastReceiver() {
    public void onReceive(Context context, Intent intent) {

        NetworkHandler.NetworkInfo netInfo = NetworkHandler.handleBcastReceiver(context);

        if (netInfo!=null){
            handleInfoChange(netInfo);
        } else {
            handleInfoChange(null);
        }
    }
};

registerNetRcvr 是从 onResume 函数中调用的(同样我有一个从 onPause 调用的取消注册)。

从上面可以看出,我有一个函数 (handleBcastReceiver) 被调用来处理 onReceive 事件,因此有另一个类,然后有各种从这个函数调用的私有函数。

只是让事情稍微复杂一点...在调用 onReceive 函数时,如上所述,“handleBcastReceiver”函数将需要“检索”正确的数据...并且因此会调用实际检索相应的系统数据如下:

private static NetworkInfo getWiFiNetworkInfo(Context context) {

    ConnectivityManager connManager = (ConnectivityManager)
            context.getSystemService(Context.CONNECTIVITY_SERVICE);
    return connManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
}

我认为我应该模拟 onReceive 回调的行为,但我猜想模拟在调用 getWiFiNetworkInfo 期间从系统返回的内容。

我的想法是我应该使用 RoboElectric 来执行此操作,因为它会影响 BroadcastReceiver/ConnectivityManager。我也看过 Mockito,但我相信 RoboElectric 是我需要的,但我接受我很可能是错的。据我所知,RoboElectric 可以让我模拟“Android 系统”,而 Mockito 可以让我模拟自己的课程。

目前我只是看不到如何测试广播接收器。此外,我不清楚我是否应该运行模拟器来执行此操作,或者只是“运行”我的单元测试,因为“影子”应该包含我需要的一切。最后,如果我要遮蔽广播接收器,我如何通过这个遮蔽过程让 WIFI 被“启用”或“禁用”?事实上,我应该模拟 BroadcastReceiver 还是只模拟 ConnectivityManager……我真的很困惑!

到目前为止,我所做的是在我的应用程序的测试部分(不是“androidTest”部分)中创建一个 BroadcastReceiverTest 类。我可以对函数进行正常的简单单元测试,我只是坚持如何模拟这种“系统”行为。

与往常一样,非常感谢任何帮助。

【问题讨论】:

  • 有问题 - 为了测试 android 应用程序,您需要以特定的、可测试的方式对其进行修正。这就是为什么 MVP 和类似的技术现在非常流行的原因。
  • BroadcastReceiver 的几个问题。对于以 N 或更高版本为目标的应用程序,不推荐以 CONNECTIVITY_CHANGE 为目标。接收者也应该检查它得到的动作是它订阅的——以避免恶意请求。

标签: android unit-testing mockito robolectric android-broadcastreceiver


【解决方案1】:

所以,我想我已经解决了... :) 如果有更多经验的人希望对此提供反馈,我们将不胜感激。

我觉得我不需要更多地关心“广播接收器”,所以我需要为 ConnectivityManager 遮蔽,因为这是“handleBcastReceiver”函数最终会从中读取的内容。所以,这才是真正重要的,因为它是我的函数中的“馈送”,它驱动着它们的行为方式。当 onReceive 函数被触发时,它会做的只是 'handleBcastReceiver' 函数,然后用结果更新 UI,因此这不是我真正需要在这里测试的。

我创建了以下内容,它对我有用。如果我修改我的测试数据,测试将适当地失败,所以我相信这是令人满意的。我希望其他人会发现它有用,正如我所提到的,我很高兴收到关于我所做的是否正确的反馈。

@RunWith(RobolectricTestRunner.class)
@Config(constants = BuildConfig.class, sdk = 23, manifest = "/src/main/AndroidManifest.xml")
public class NetworkStateHandlerUnitTest {

    private static String NETWORK_TYPE_HSDPA = "HSDPA";
    private ConnectivityManager connectivityManager;
    private ShadowConnectivityManager shadowConnectivityManager;
    private Context context;

    @Before
    public void setUp() {

    }

    @Test
    public void handleBroadcastReceiverWIFIConnected() {

        context = RuntimeEnvironment.application.getApplicationContext();
        connectivityManager = getConnectivityManager();
        shadowConnectivityManager = Shadows.shadowOf(connectivityManager);

        //Create shadow Network Info - Connected, WIFI, No Subtype, available, connected
        NetworkInfo networkInfoShadow = ShadowNetworkInfo.newInstance(NetworkInfo.DetailedState.CONNECTED, ConnectivityManager.TYPE_WIFI, 0, true, true);
        shadowConnectivityManager.setNetworkInfo(ConnectivityManager.TYPE_WIFI, networkInfoShadow);

        NetworkHandler.NetworkInfo networkInfoResponse;

        //Call the function under test
        networkInfoResponse = NetworkHandler.handleBcastReceiver(context);

        //Validate the response
        assertEquals(networkInfoResponse.getNetworkType(), ConnectivityManager.TYPE_WIFI);
    }

    private ConnectivityManager getConnectivityManager() {
        return (ConnectivityManager) RuntimeEnvironment.application.getSystemService(context.CONNECTIVITY_SERVICE);
    }
}

当然,我做的不仅仅是这一项测试,但我觉得这足以帮助其他发现自己同样陷入困境的人:)

很高兴地说,最终我也设法测试了 BroadcastReceiver 侦听器...如果您想知道如何执行此操作...

@Test
public void handleBrcastRcvrWifiConn() {

    MainActivity activity = Robolectric.setupActivity(MainActivity.class);
    TextView tvConnStatus = (TextView) activity.findViewById(R.id.tvConnectionState);


    context = RuntimeEnvironment.application.getApplicationContext();
    connectivityManager = getConnectivityManager();
    shadowConnManager = Shadows.shadowOf(connectivityManager);

    //Create shadow Network Info - Connected, WIFI, No Subtype, available, connected
    NetworkInfo netInfoShadow = ShadowNetworkInfo.newInstance(NetworkInfo.DetailedState.CONNECTED,
            ConnectivityManager.TYPE_WIFI, 0, true, true);
    shadowConnManager.setNetworkInfo(ConnectivityManager.TYPE_WIFI, networkInfoShadow);


    //Trigger BroadcastReceiver
    RuntimeEnvironment.application.sendBroadcast(new Intent("android.net.wifi.STATE_CHANGE"));

    //Validate result by checking value of textView
    assertEquals("Connected", tvConnectionState.getText());

}

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多