在 AndroidAnnotations SharedPreferences 中模拟链式方法调用
Mocking chained method calls in AndroidAnnotations SharedPreferences
在我正在使用的项目中 AndroidAnnotations to generate SharedPreferences:
import org.androidannotations.annotations.sharedpreferences.DefaultBoolean;
import org.androidannotations.annotations.sharedpreferences.SharedPref;
@SharedPref(value = SharedPref.Scope.UNIQUE)
public interface MySharedPreferences {
@DefaultBoolean(false)
boolean enabled();
}
生成的class可以如下使用:
preferences.enabled().get();
preferences.enabled().put(true);
我正在尝试编写一个检查某些逻辑的单元测试。在那里我想模拟偏好:
@Mock MyPreferences_ prefs;
MyLogic logic;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
logic = new Logic();
}
@Test
public void testEnabled() throws Exception {
when(prefs.enabled().get()).thenReturn(false);
assertThat(logic.isEnabled()).isEqualTo(false);
}
但是,访问 prefs.enabled()
会引发 NullPointerException
:
java.lang.NullPointerException
at com.example.MyLogicTest.isValuesStoredProperly(MyLogicTest.java) ...
是否可以使用 Mockito 模拟链式方法调用(包括空对象)?
更新
作为基于 的更新,我将我的实现更改如下:
public class MyLogicTest {
@Mock SharedPreferences prefs;
@Mock CustomSharedPreferences_ prefs_;
MyLogic logic;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
logic = new MyLogic();
}
@Test
public void testEnabled() throws Exception {
MockPrefs mockPrefs = new MockPrefs(prefs);
when(prefs_.enabled()).thenReturn(mockPrefs.getEnabledPrefField());
doNothing().when(prefs_.enabled()).put(anyBoolean()); // <-- fails
when(prefs_.enabled().get()).thenReturn(false);
assertThat(logic.isEnabled()).isEqualTo(false);
}
private class MockPrefs extends SharedPreferencesHelper {
public MockPrefs(SharedPreferences sharedPreferences) {
super(sharedPreferences);
}
public BooleanPrefField getEnabledPrefField() {
return super.booleanField("enabled", enabledOld);
}
}
}
这里仍然失败:
doNothing().when(prefs_.enabled()).put(anyBoolean());
来自 prefs_.enabled()
的 BooleanPrefField
对象是 final
并且不能被模拟。
org.mockito.exceptions.misusing.UnfinishedStubbingException:
Unfinished stubbing detected here:
-> at MyLogicTest.testEnabled
E.g. thenReturn() may be missing.
Examples of correct stubbing:
when(mock.isOk()).thenReturn(true);
when(mock.isOk()).thenThrow(exception);
doThrow(exception).when(mock).someVoidMethod();
Hints:
1. missing thenReturn()
2. you are trying to stub a final method, which is not supported
3: you are stubbing the behaviour of another mock inside before 'thenReturn' instruction if completed
示例项目
解决方案
- 请在上面的示例项目中找到工作。
您是否尝试过 运行 使用 @RunWith(MockitoJUnitRunner.class)
而不是 MockitoAnnotations
进行测试?跑步者应该自动初始化所有 @Mock
注释字段并摆脱 NPE。
也许关注 answer 可以进一步帮助您。
为了模拟链式方法调用,您可以在 MyPreferences_
中使用此注释
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
.
但我建议您模拟调用 prefs.enabled()
的结果。
@Mock
BooleanPrefField booleanPrefField;
@Test
public void testEnabled() throws Exception {
when(prefs.enabled()).thenReturn(booleanPrefField);
when(booleanPrefField.get()).thenReturn(false);
assertThat(logic.isEnabled()).isEqualTo(false);
}
注意:您应该将 MyObject
替换为 prefs.enabled()
return 的对象类型。使用这种方式,您可以更好地控制方法调用的行为。
更新:如果 BooleanPrefField
是最终的,您可以简单地 return 在您的模拟中 class 的一个对象。
when(prefs.enabled()).thenReturn(SharedPreferencesHelper.booleanField("", false));
在我正在使用的项目中 AndroidAnnotations to generate SharedPreferences:
import org.androidannotations.annotations.sharedpreferences.DefaultBoolean;
import org.androidannotations.annotations.sharedpreferences.SharedPref;
@SharedPref(value = SharedPref.Scope.UNIQUE)
public interface MySharedPreferences {
@DefaultBoolean(false)
boolean enabled();
}
生成的class可以如下使用:
preferences.enabled().get();
preferences.enabled().put(true);
我正在尝试编写一个检查某些逻辑的单元测试。在那里我想模拟偏好:
@Mock MyPreferences_ prefs;
MyLogic logic;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
logic = new Logic();
}
@Test
public void testEnabled() throws Exception {
when(prefs.enabled().get()).thenReturn(false);
assertThat(logic.isEnabled()).isEqualTo(false);
}
但是,访问 prefs.enabled()
会引发 NullPointerException
:
java.lang.NullPointerException at com.example.MyLogicTest.isValuesStoredProperly(MyLogicTest.java) ...
是否可以使用 Mockito 模拟链式方法调用(包括空对象)?
更新
作为基于
public class MyLogicTest {
@Mock SharedPreferences prefs;
@Mock CustomSharedPreferences_ prefs_;
MyLogic logic;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
logic = new MyLogic();
}
@Test
public void testEnabled() throws Exception {
MockPrefs mockPrefs = new MockPrefs(prefs);
when(prefs_.enabled()).thenReturn(mockPrefs.getEnabledPrefField());
doNothing().when(prefs_.enabled()).put(anyBoolean()); // <-- fails
when(prefs_.enabled().get()).thenReturn(false);
assertThat(logic.isEnabled()).isEqualTo(false);
}
private class MockPrefs extends SharedPreferencesHelper {
public MockPrefs(SharedPreferences sharedPreferences) {
super(sharedPreferences);
}
public BooleanPrefField getEnabledPrefField() {
return super.booleanField("enabled", enabledOld);
}
}
}
这里仍然失败:
doNothing().when(prefs_.enabled()).put(anyBoolean());
来自 prefs_.enabled()
的 BooleanPrefField
对象是 final
并且不能被模拟。
org.mockito.exceptions.misusing.UnfinishedStubbingException:
Unfinished stubbing detected here:
-> at MyLogicTest.testEnabled
E.g. thenReturn() may be missing.
Examples of correct stubbing:
when(mock.isOk()).thenReturn(true);
when(mock.isOk()).thenThrow(exception);
doThrow(exception).when(mock).someVoidMethod();
Hints:
1. missing thenReturn()
2. you are trying to stub a final method, which is not supported
3: you are stubbing the behaviour of another mock inside before 'thenReturn' instruction if completed
示例项目
解决方案
- 请在上面的示例项目中找到工作。
您是否尝试过 运行 使用 @RunWith(MockitoJUnitRunner.class)
而不是 MockitoAnnotations
进行测试?跑步者应该自动初始化所有 @Mock
注释字段并摆脱 NPE。
也许关注 answer 可以进一步帮助您。
为了模拟链式方法调用,您可以在 MyPreferences_
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
.
但我建议您模拟调用 prefs.enabled()
的结果。
@Mock
BooleanPrefField booleanPrefField;
@Test
public void testEnabled() throws Exception {
when(prefs.enabled()).thenReturn(booleanPrefField);
when(booleanPrefField.get()).thenReturn(false);
assertThat(logic.isEnabled()).isEqualTo(false);
}
注意:您应该将 MyObject
替换为 prefs.enabled()
return 的对象类型。使用这种方式,您可以更好地控制方法调用的行为。
更新:如果 BooleanPrefField
是最终的,您可以简单地 return 在您的模拟中 class 的一个对象。
when(prefs.enabled()).thenReturn(SharedPreferencesHelper.booleanField("", false));