我在我的课程中有一个私有字段,并且如果设置了某个标志并且如果映射包含某个值,则该方法会对其进行修改。我想测试该方法并查看结果。这是代码(为简洁起见,省略了不相关的字段和方法):
我的课程:
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);
}
}
运行测试时,在NullPointerException
类中得到UsersLoader
,与IF子句一致,该子句检查status.get(SOME_KEY)
。即使我解决了该问题,下一个NPE也会在下面一行,因为我的users
为空。如何在模拟的类中初始化私有字段,以便可以使用它们?我可以创建一个getter和setter并模拟它们,但是随后整个测试就失去了意义。
答案 0 :(得分:3)
您可以使用间谍代替模拟游戏。
这将触发构造函数,并为私有变量分配一个空列表,从而使NPE转义:
private UsersLoader loader;
@Before
public void setUp() {
loader = spy(new UsersLoader());
}
现在您无需拨打电话:
doCallRealMethod().when(loader).loadExternalUsers(anyBoolean());
请记住,您需要模拟不需要在实现时触发的任何方法。
答案 1 :(得分:1)
首先,将初始化移动到字段的声明:
private Collection<User> users = new ArrayList<>();
然后,您可以使用自己的模拟程序注入该字段:
@RunWith(MockitoJUnitRunner.class)
class UsersLoaderTest {
@Mock
private Collection<User> users;
@InjectMocks
private UsersLoader loader;
}
,然后验证是否与您期望的用户一起调用users.add()
。
答案 2 :(得分:1)
不要模拟UsersLoader.class,这是包含要测试的方法的类。创建模拟时,将不会实现模拟的类,而是可以模拟该类的功能。宁可监视它,也可以仅实例化并提供检查功能的手写检查。在后一种情况下,您根本不需要Mockito。因此,您可以对其进行监视并使用嘲笑功能来测试功能