如何在单元测试中创建Bundle

时间:2016-11-02 14:47:29

标签: java android unit-testing junit android-testing

我想测试一个处理Bundles的方法。但是,我无法在测试环境中创建(非null)Bundle对象。

给出以下代码:

Bundle bundle = new Bundle();
bundle.putString("key", "value");
boolean containsKey = bundle.containsKey("key");
如果代码在应用程序上下文中执行,则

containsKeytrue,如果在单元测试中执行,则为false

Service Context

Test Context

我无法弄清楚为什么会这样,以及如何为我的测试创建一个Bundle。

3 个答案:

答案 0 :(得分:15)

如果您的构建脚本包含以下内容:

testOptions {
    unitTests.returnDefaultValues = true
}

然后这就是为什么即使你没有为Bundle类指定模拟,你的测试也不会失败的原因。

有几种方法可以解决这个问题:

  1. 使用Mockito模拟框架来模拟Bundle类。不幸的是,你必须自己编写很多样板代码。例如,您可以使用此方法来模拟bundle对象,因此它将通过 getString 方法返回正确的值:

     @NonNull
     private Bundle mockBundle() {
           final Map<String, String> fakeBundle = new HashMap<>();
           Bundle bundle = mock(Bundle.class);
           doAnswer(new Answer() {
           @Override
           public Object answer(InvocationOnMock invocation) throws Throwable {
                 Object[] arguments = invocation.getArguments();
                 String key = ((String) arguments[0]);
                 String value = ((String) arguments[1]);
                 fakeBundle.put(key, value);
                 return null;
           }
           }).when(bundle).putString(anyString(), anyString());
           when(bundle.get(anyString())).thenAnswer(new Answer<String>() {
                  @Override
                  public String answer(InvocationOnMock invocation) throws Throwable {
                       Object[] arguments = invocation.getArguments();
                       String key = ((String) arguments[0]);
                       return fakeBundle.get(key);
                   }
           });
           return bundle;
      }
    
  2. 使用Robolectric框架为您的单元测试提供某种影子类。这允许您在单元测试中使用Android特定类,并且它们将正常运行。通过使用该框架,您的单元测试将在几乎没有任何变化的情况下正常运行。

  3. 我猜你最不受欢迎,但是,这是合格的。您可以使您的测试功能正常,并在您的Android设备或模拟器上运行它。因为速度,我不建议那样。在执行测试之前,您必须构建测试apk,安装并运行。如果您要进行TDD,这是非常慢的。

答案 1 :(得分:1)

使用Mockito,您可以执行以下操作:

one.py
现在,

containsKey 在要测试的类中为true。

有关when()的一些其他信息。当使用when()包装模拟对象方法调用时,它将跳过该方法的实际实现,并立即返回thenReturn()部分提供的值。在编写某些单元测试时,这是一个救命稻草,因为一旦方法调用到它的“兔子洞”中,它可能会成为噩梦。

这是我找到的设置通往实际要测试代码的路径的最佳方法。

答案 2 :(得分:0)

我最终使用了Mockito:

// Returns Stackoverflow as it is the only documentation that has the type Q&A
let ref = this.firebase.database().ref().child('documentation').orderByChild('type').equalTo('Q&A').on('value', snap => {
  doc = snap.val();
  console.log(doc);
});

由于我不需要测试很多在bundle中传递的参数,我嘲笑他们这样的调用:

Bundle extras = mock(Bundle.class);

我向团队提出的建议是用Java模拟替换Bundle用法。