android - 使用 Mockito 模拟 PreferenceManager

标签 android unit-testing junit mockito tdd

我是 Android 单元测试的新手,我想在现有项目中添加一些单元测试。我正在使用 MVP 设计架构。在我的演示者中,我调用了 PreferenceManager 以获得默认的 SharedPrefences 但它始终返回 null。我在 stackoverflow 上遵循了一些关于如何模拟 PreferenceManagerSharedPreferences 的教程和建议,但我无法让它工作。这是我的主讲类

@RunWith(MockitoJUnitRunner.class)
public class SettingsPresenterTest {
    @Mock
    private SettingsView mView;
    @Mock
    private LocalConfiguration conf;
    private SettingsPresenter mPresenter;

    public SettingsPresenterTest() {
        super();
    }

    @Before
    public void startUp() throws Exception {
        MockitoAnnotations.initMocks(LocalConfiguration.class);
        MockitoAnnotations.initMocks(PreferenceManager.class);


        mPresenter = new SettingsPresenter(mView);


        final SharedPreferences sharedPrefs = 
        Mockito.mock(SharedPreferences.class);
        final Context context = Mockito.mock(Context.class);

       Mockito.when(PreferenceManager.getDefaultSharedPreferences(context)).
       thenReturn(sharedPrefs);
    }


    @Test
    public void notificationsEnabledClicked() throws Exception {
        boolean notifsEnabled = false;
        mPresenter.notificationsEnabledClicked(notifsEnabled);

        Mockito.verify(mView).setNotificationsView(notifsEnabled);
    }
}

这里是 SharedPreferences 返回 null 的方法

public class LocalConfiguration { 
    public TerritoryDto getLastSavedTerritory() {
           SharedPreferences preferences = 
           PreferenceManager.getDefaultSharedPreferences(H.getContext());
           String terrritoryString = preferences.getString(SAVED_TERRITORY, 
           null);
           return 
           SerializerHelper.getInstance().deserialize(terrritoryString, 
           TerritoryDto.class);
    }
}

你能给我一些关于如何解决这个错误的指南吗?

最佳答案

与其直接引用 Android SDK,不如从您的呈现器逻辑中抽象出来。这意味着,不是执行 PreferenceManager.getDefaultSharedPreferences(),而是创建一个抽象并从您的抽象中请求 territoryString

这会给你带来什么,你的演示者不会知道来自 Android SDK 的 PreferenceManagerSharedPreferences 的precense,因此你会有足够的接缝来执行纯单元测试。

说到这里,让我们来实现抽象。声明了以下接口(interface):


    public interface Storage {
        @Nullable
        String getSavedTerritory();
    }

具体实现是:


    public SharedPrefsStorage implements Storage {

        private final SharedPreferences prefs;

        public SharedPrefsStorage(Context context) {
            prefs = PreferenceManager.getDefaultSharedPreferences();
        }

        @Nullable
        @Override
        public String getSavedTerritory() {
            return prefs.getString(SAVED_TERRITORY, null);
        }

    }

那么你的presenter会变成这样:


    public class LocalConfiguration { 

        final Storage storage;

        public LocalConfiguration(Storage storage) {
            this.storage = storage;
        }

        public TerritoryDto getLastSavedTerritory() {
               final String territory = storage.getSavedTerritory();

               return SerializerHelper.getInstance().deserialize(territory, TerritoryDto.class);
        }
    }

这会给你一个接缝来执行纯单元测试:


    @Test
    void someTest() {
        when(storage.getSavedTerritory()).thenReturn("New York");
        ...
    }

再也不用担心模拟 PreferenceManager 了。

关于android - 使用 Mockito 模拟 PreferenceManager,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46886351/

相关文章:

android - 如何在 Android 的动态链接器中启用调试输出?

java - 在 Webdriver 中创建测试套件

java - 使用模拟验证错误消息,其中结果可以根据 id 更改

安卓 : orientation issue

android - 我应该将图像放在 eclipse 资源文件夹中的什么位置?

android - action.PROCESS_TEXT Activity 未在 Oreo 的 EditText 中列出

unit-testing - Nestjs 单元测试 - 模拟方法守卫

java - 如何从命令行运行 JUnit 测试用例

java - mvn 单元测试公共(public)资源文件夹和读取文件功能

intellij-idea - 如何使用 VisualVM 分析从 Intellij Idea 运行的 JUnit 测试