测试仍然从真正的SharedPreferences中读取

时间:2015-11-17 06:03:20

标签: java android mockito

我做了一个简单的检测测试,以验证从SharedPreferences读取的数据是否在UI上正确显示。在Activity的onResume()方法中执行数据检索和显示操作。
但问题是,即使我嘲笑了偏好对象并定义了假的返回值,活动仍然从真实偏好中读取数据,忽略when(...).thenReturn(...)声明。任何人都可以有什么想法吗?

@RunWith(AndroidJUnit4.class)
public class EditProfileActivityTest {

    @Mock
    private UserPreference userPreference;
    private String FAKE_NAME = "Test";

    @Rule
    public ActivityTestRule<EditProfileActivity> activityTestRule = new ActivityTestRule(EditProfileActivity.class,true,false);

    @Before
    public void setUp(){

        //Set fake SharedPreferences
        MockitoAnnotations.initMocks(this);
        when(userPreference.getName()).thenReturn(FAKE_NAME);

        //Start Activity
        Intent intent = new Intent();
        activityTestRule.launchActivity(intent);
    }

    @Test
    public void showUserData() throws Exception{
        onView(withId(R.id.name_tv)).check(matches(withText(FAKE_NAME)));
    }
}    

其中UserPreference是一个自定义类,它只包装SharedPreference类并包含许多getter和setter。这是它的构造函数

 
public UserPreference(Context context) {
    this.context = context;
    sharedPreferences = this.context.getSharedPreferences("Pref", Context.MODE_PRIVATE);
    prefEditor = sharedPreferences.edit();
}  

和其中一个吸气剂和二传手:

 
public String getName() {
    return sharedPreferences.getString(context.getString(R.string.pref_name), "Guest");
}    
public void saveName(String name){
    prefEditor.putString(context.getString(R.string.pref_name), name);
    prefEditor.apply();
}

[编辑]
我原始活动的简化版本:

 
public class EditProfileActivity extends AppCompatActivity{
    //...
    private UserPreference userPreference;
    //...

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        userPreference = new UserPreference(this);
        setContentView(R.layout.activity_edit_profile);
        //...
    }
    @Override
    protected void onResume() {
        super.onResume();
        //...
        String name = userPreference.getName();
        nameEdt.setText(name);  //Display the name on an EditText
        //...
    }
}

1 个答案:

答案 0 :(得分:0)

创建了onCreate模拟,但活动仍然使用在其userPreference方法中创建的模拟。您需要将该活动的userPreference字段设置为模拟。

有几种方法可以做到:

  • @Before字段添加setter方法,并使用@Before public void setUp(){ ... EditProfileActivity activity = activityTestRule.launchActivity(intent); activity.setUserPreference(mockedUserPreference); } 方法调用它:

    userPreference

    这很简单但很难看:你改变活动只是为了适应测试。

  • 通过反射设置@Before public void setUp(){ ... EditProfileActivity activity = activityTestRule.launchActivity(intent); Field userPreferenceField = activity.getClass().getDeclaredField("userPreference"); field.setAccessible(true); userPreferenceField.set(activity, mockedUserPreference); } 字段:

    UserPreference

    这是一个脆弱的测试:更改字段名称会破坏它而不会出现编译错误。但是,活动不必改变,所以当你无法改变它时它很有用。

  • 不要在onCreate方法中实例化fiddler auto responder rule editor。在普通的Java中,我将它添加为构造函数参数,但我不知道这是否适用于Android。也许使用依赖注入框架,它们非常适合用于模拟:Android and Dependency Injection