在 AndroidAnnotations SharedPreferences 中模拟链式方法调用



在一个项目中,我正在使用AndroidAnnotations来生成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();
}

生成的类可以按如下方式使用:

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.isValuesStorageProperly(MyLogicTest.java( ...

是否可以使用 Mockito 模拟链式方法调用(包括空对象(?

更新

作为基于 alayor 有用建议的更新,我更改了我的实现,如下所示:

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

示例项目

  • 简化的示例项目

溶液

  • 请在上面的示例项目中找到工作。
为了

模拟链式方法调用,您可以在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()返回的对象类型。使用这种方式,您可以更好地控制方法调用的行为。

更新:如果BooleanPrefField是最终的,你可以简单地在模拟中返回该类的对象。

when(prefs.enabled()).thenReturn(SharedPreferencesHelper.booleanField("", false));
您是否

尝试过使用 @RunWith(MockitoJUnitRunner.class) 而不是 MockitoAnnotations 运行测试?运行器应自动初始化所有@Mock注释字段并删除该 NPE。

也许以下答案可以进一步帮助您。

相关内容

  • 没有找到相关文章

最新更新