【问题标题】:Unit test fails when BroadcastReceiver sends an Intent to an IntentService当 BroadcastReceiver 向 IntentService 发送 Intent 时单元测试失败
【发布时间】:2018-11-27 10:01:07
【问题描述】:

我有一个BroadcastReceiver,它以IntentService 开头:

@Override
public void onReceive(Context context, Intent intent) {

    ParamsRequest paramsRequest = new ParamsRequest.Builder()
            .setUrl(intent.getStringExtra("url"))
            .build();

    Intent serviceIntent = new Intent(context, MyIntentService.class);
    serviceIntent.putExtra("paramsKey", paramsRequest);
    context.startService(serviceIntent);
}

MyIntentService 检索Intent(带有对象paramsRequest):

@Override
protected void onHandleIntent(Intent intent) {

    ParamsRequest paramsRequest = (ParamsRequest) intent.getSerializableExtra("paramsKey");

    //more code
}

我有一个测试来确保正确发送和检索意图:

@Test
public void testStartAndroidProofService() {
    Intent intent = new Intent(context, AndroidProofService.class);
    intent.putExtra("paramsKey", paramsRequest);

    receiver.onReceive(context, intent);
    assertNull(receiver.getResultData());

    ArgumentCaptor<Intent> argumentIntent = ArgumentCaptor.forClass(Intent.class);
    Mockito.verify(context, times(1)).startService(argumentIntent.capture());
    assertEquals(paramsRequest, argumentIntent.getValue().getSerializableExtra("paramsKey"));
}

但是AssertEquals 失败了:

知道为什么我有 2 个不同的对象吗?

编辑:argumentIntent.capture() 中捕获的Intent 包含一个ParamsRequest 对象,但该对象中的所有字段都是null

【问题讨论】:

    标签: android unit-testing broadcastreceiver intentservice


    【解决方案1】:

    这是关于序列化的。

    当您将ParamsRequest 放入Intent 时,在底层,ParamsRequest 中的所有字段都将转换为字符串、布尔值、整数等,以便可以存储它们。稍后,当您从 Intent 检索 ParamsRequest 时,将收集所有这些值并创建一个新的 ParamsRequest。因此,第一个 ParamsRequest 和第二个 ParamsRequest 是不同的对象,然后你会得到一个断言错误。

    您在这里要做的是比较每个字段或ParamsRequest 或覆盖equalsParamsRequest

    【讨论】:

    • 感谢您的回复。你说的有道理,所以现在我正在比较对象的字段,我意识到检索到的对象具有null 的所有字段,所以我的测试有问题。
    【解决方案2】:

    好吧,我终于知道是怎么回事了。问题的根源在于我对流程的想法是错误的:

    1. 构建一个Intent 并将ParamsRequest 设置为额外的
    2. 将此Intent 传递给BroadcastReceiver 通过onReceive()
    3. onReceive() 对数据进行操作Intent
    4. 拨打startService()以上Intent

    上述逻辑发现的问题:

    • 我将 ParamsRequest 对象设置为在 onReceive() 中检索到的 Intent 中的额外对象。这是错误的,因为ParamsRequest 对象必须onReceive() 内构建。

    • 我将在onReceive(Context, Intent) 中检索到的Intent 与在startService(Intent) 中发送的Intent 进行比较,就好像它们是相同的Intent。这是错误的,因为它们是不同的Intents,因为startService(Intent) 中使用的第二个Intent 是根据第一个Intent 中包含的数据构建的。

    所以固定测试是:

    @Test
    public void testStartService() {
        // I build the Intent that the onReceive() will receive
        Intent intent = new Intent();
        intent.putExtra("url", "https://fakeurl.com");
    
        //I simulate that the BroadcastReceiver is triggered, calling the onReceive() method and passing the above Intent
        receiver.onReceive(context, intent);
    
        //The actual code inside onReceive() instantiates a new Intent and calls startService(Intent)
    
        // I capture the new Intent instantiated inside the onReceive() method
        ArgumentCaptor<Intent> argumentIntent = ArgumentCaptor.forClass(Intent.class);
        Mockito.verify(context, times(1)).startService(argumentIntent.capture());
    
        //I retrieve the url from the ParamsRequest object setted in the captured Intent        
        ParamsRequest paramsRequest = (ParamsRequest) argumentIntent.getValue().getSerializableExtra("paramsRequest_key");
        String url = paramsRequest.getUrl();
        assertEquals("https://fakeurl.com", url);
    }
    

    并且测试成功通过。

    【讨论】:

      猜你喜欢
      • 2013-10-31
      • 2023-04-04
      • 2012-07-12
      • 2020-01-01
      • 2015-04-25
      • 2015-10-14
      • 1970-01-01
      • 2023-03-22
      • 1970-01-01
      相关资源
      最近更新 更多