BroadcastReceiver 向 IntentService 发送 Intent 时单元测试失败

Unit test fails when BroadcastReceiver sends an Intent to an IntentService

我有一个 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.

关于序列化。

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

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

好的,我终于知道是怎么回事了。问题的根源是我脑海中的流程是错误的:

  1. 构建一个 Intent 并将 ParamsRequest 设置为额外的
  2. 通过onReceive()
  3. 将此Intent传递给BroadcastReceiver
  4. onReceive()Intent
  5. 中的数据进行运算
  6. 用上面的Intent
  7. 调用startService()

以上逻辑发现的问题:

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

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

所以固定测试是:

@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);
}

测试成功。