【问题标题】:Mock PreferenceManager with Mockito使用 Mockito 模拟 PreferenceManager
【发布时间】:2018-04-03 19:46:38
【问题描述】:

我是 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 unit-testing junit mockito tdd


    【解决方案1】:

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

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

    说了这么多,让我们来实现抽象。声明了以下接口:

    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了。

    【讨论】:

    • 您的解决方案是有效的,但可悲的事实是我无法更改当前代码,至少目前如此,因为这是一个大项目,我已经在这里待了大约一个月,所以我不能做出这样的决定。谢谢你。不过。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-12-30
    • 2012-02-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-13
    相关资源
    最近更新 更多