首页 > 解决方案 > 在模拟类中初始化私有字段

问题描述

我的类中有一个私有字段和一个方法,如果设置了某个标志并且地图包含某个值,则该方法正在修改它。我想测试该方法并查看结果。这是代码(为简洁起见,省略了不相关的字段和方法):

我的课:

class UsersLoader {
   private Collection<User> users;
   private Map<Integer,Boolean> status;

   UsersLoader() {
      users = new ArrayList<>();
      status = new HashMap<>();
   }

   protected loadExternalUsers(boolean condition) {
      Collection<User> externalUsers = LoadUsersFromSomeExternalSource();
      if (condition && status.get(SOME_KEY)) {
         users.addAll(externalUsers);
      } else {
         /* do not modify my users */
      }
   }
}

我的测试:

import static org.mockito.Mockito.mock;

public class UsersLoaderTest {
   private UsersLoader loader;

   @Before
   public void setUp() {
      loader = mock(UsersLoader.class);
      doCallRealMethod().when(loader).loadExternalUsers(anyBoolean());
   }

   @Test
   public void testLoadingWhenFlagIsTrue {
      Collection<User> users = loader.loadExternalUsers(true);
      assertThat(users.size() == 1);
   }

   @Test
   public void testLoadingWhenFlagIsFalse {
      Collection<User> users = loader.loadExternalUsers(false);
      assertThat(users.size() == 0);
   }

}

当我运行测试时,我得到了一个NullPointerExceptionin UsersLoaderclass,与检查status.get(SOME_KEY). 即使我解决了这个问题,下一个 NPE 也将是下面的一行,因为 myusers将为空。如何在我的模拟类中初始化私有字段以便我可以使用它们?我可以创建一个 getter 和一个 setter 并模拟它们,但是整个测试就失去了意义。

标签: javaunit-testingjunitmockito

解决方案


在您的情况下,您可以使用Spy而不是模拟。

这将触发构造函数并将一个空列表分配给私有变量,从而逃避 NPE:

private UsersLoader loader;

@Before
public void setUp() {
  loader = spy(new UsersLoader());
}

现在您不需要进行此调用:

  doCallRealMethod().when(loader).loadExternalUsers(anyBoolean());

请记住,您需要模拟任何不需要在实现时触发的方法。


推荐阅读