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
或覆盖 ParamsRequest
的 equals
。
好的,我终于知道是怎么回事了。问题的根源是我脑海中的流程是错误的:
- 构建一个
Intent
并将 ParamsRequest
设置为额外的
- 通过
onReceive()
将此Intent
传递给BroadcastReceiver
onReceive()
对Intent
中的数据进行运算
- 用上面的
Intent
调用startService()
以上逻辑发现的问题:
我将 ParamsRequest
对象设置为在 onReceive()
中检索到的 Intent
中的额外对象。这是错误的,因为 ParamsRequest
对象必须构建在 内部 onReceive()
.
我将 onReceive(Context, Intent)
中检索到的 Intent
与 startService(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);
}
测试成功。
我有一个 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
或覆盖 ParamsRequest
的 equals
。
好的,我终于知道是怎么回事了。问题的根源是我脑海中的流程是错误的:
- 构建一个
Intent
并将ParamsRequest
设置为额外的 - 通过
onReceive()
将此 onReceive()
对Intent
中的数据进行运算
- 用上面的
Intent
调用
Intent
传递给BroadcastReceiver
startService()
以上逻辑发现的问题:
我将
ParamsRequest
对象设置为在onReceive()
中检索到的Intent
中的额外对象。这是错误的,因为ParamsRequest
对象必须构建在 内部onReceive()
.我将
onReceive(Context, Intent)
中检索到的Intent
与startService(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);
}
测试成功。