使用 Mockito 模拟 PreferenceManager

ant*_*_st 5 tdd junit android unit-testing mockito

我是 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);
    }
}
Run Code Online (Sandbox Code Playgroud)

这是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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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

azi*_*ian 3

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

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

话虽如此,让我们实现抽象。已声明以下接口:


    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);
        }

    }

那么你的演示者就会变成这样:


    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