Can someone please show me a working unit test om this code, using mockito? Im new to testing in Android studio and could really need some help.
public class PreferenceHelper {
public static final String SHARED_PREFS_NAME = "EDUBACK_PREFS";
public static final String PREF_KEY_IS_STUDENT = "PREF_KEY_IS_STUDENT";
private final SharedPreferences mPref;
public PreferenceHelper(Context context) {
mPref = context.getSharedPreferences(SHARED_PREFS_NAME, Context.MODE_PRIVATE);
}
public void setIsStudent(boolean isStudent) {
mPref.edit().putBoolean(PREF_KEY_IS_STUDENT, isStudent).apply();
}
public boolean getIsStudent() {
return mPref.getBoolean(PREF_KEY_IS_STUDENT, true); // Default true
}}
Actually it is not necessary to use mockito here.
You can test your class something like that (for assertions I use org.assertj:assertj-core:3.5.2 library):
#RunWith(RobolectricTestRunner.class)
public class PreferenceHelperTest {
private SharedPreferences sharedPreferences;
private PreferenceHelper preferenceHelper;
#Before
public void setUp() {
sharedPreferences = RuntimeEnvironment.application.getSharedPreferences(SHARED_PREFS_NAME, Context.MODE_PRIVATE);
preferenceHelper = new PreferenceHelper(ShadowApplication.getInstance().getApplicationContext());
}
#Test
public void setIsStudent_whenIsStudentIsTrue() {
preferenceHelper.setIsStudent(true);
assertThat(sharedPreferences.getBoolean(PREF_KEY_IS_STUDENT, false)).isTrue();
}
#Test
public void setIsStudent_whenIsStudentIsFalse() {
preferenceHelper.setIsStudent(false);
assertThat(sharedPreferences.getBoolean(PREF_KEY_IS_STUDENT, true)).isFalse();
}
#Test
public void getIsStudent_whenIsStudentIsNull() {
boolean getIsStudent = preferenceHelper.getIsStudent();
assertThat(getIsStudent).isTrue();
}
#Test
public void getIsStudent_whenIsStudentIsFalse() {
preferenceHelper.setIsStudent(false);
boolean getIsStudent = preferenceHelper.getIsStudent();
assertThat(getIsStudent).isFalse();
}
#Test
public void getIsStudent_whenIsStudentIsTrue() {
preferenceHelper.setIsStudent(true);
boolean getIsStudent = preferenceHelper.getIsStudent();
assertThat(getIsStudent).isTrue();
}
}
Related
Im our app, we have a class with app preferences, that stores certain data. A short version of this class looks like this:
public class AppPreferences
{
private ISharedPreferences mSharedPrefs;
private ISharedPreferencesEditor mPrefsEditor;
private Context mContext;
public AppPreferences(Context context)
{
this.mContext = context;
mSharedPrefs = PreferenceManager.GetDefaultSharedPreferences(mContext);
mPrefsEditor = mSharedPrefs.Edit();
}
public void SaveAutoLogIn(bool autologindone)
{
mPrefsEditor.PutBoolean(AUTOLOGIN, autologindone);
mPrefsEditor.Commit();
}
public bool GetSaveAutoLogIn()
{
return mSharedPrefs.GetBoolean(AUTOLOGIN, false);
}
public void saveLocationPermissionGranted(bool granted)
{
mPrefsEditor.PutBoolean(LOCATIONPERMISSION, granted);
mPrefsEditor.Commit();
}
public void savePermissionGranted(bool granted)
{
mPrefsEditor.PutBoolean(PERMISSIONS, granted);
mPrefsEditor.Commit();
}
}
But instead of continuesly instantiating this class in every activity it is needed in, I have decided to create a singleton class (Shorted):
class Preferences : AbstractPreferences<Preferences>
{
// öffentliche Felder und Methoden
public string usernameKey { get; set; }
public string emailKey { get; set; }
public int numberOfNews { get; set; }
public bool locationpermission { get; set; }
public int numberofnewschats { get; set; }
AppPreferences ap;
private Preferences()
{
}
public void GetPreferences(Context mContext)
{
ap = new AppPreferences(mContext);
this.usernameKey = ap.getUsernameKey();
this.emailKey = ap.getEmailKey()
}
public void DeletePreferences()
{
ap.deletePreferences();
}
public void DeleteTutorialPrefs()
{
ap.deleteTutorialPrefs();
}
public void SetPreferencesDeviceID(string key)
{
ap.saveDeviceID(key);
}
}
Okay, so basically, this class that inherets from:
public abstract class AbstractPreferences<T> where T : class
{
// Lazy Instanziierung
private static readonly Lazy<T> _instance = new Lazy<T>(() => CreateSingletonInstance());
public static T Instance
{
get
{
// throw new System.InvalidOperationException("out");
return _instance.Value;
}
}
private static T CreateSingletonInstance()
{
// Konstruktion des Singleton-Objekts
return Activator.CreateInstance(typeof(T), true) as T;
}
}
}
Now instantiates all app preferences at once and then sets them to an object like:
Preferences.Preferences prf = Preferences.Preferences.Instance;
prf.GetPreferences(mContext);
This was neccissarry, since any other way caused the app preferences to crash. But here is the problem:
I cannot SET any prefs. Retrieving them works just fine - but when I set a value, like a bool set to true - after I retrieve just this value, I get the default value in return (false). I debugged this as far as I could. When I am in the first class (AppPreferences) I see that the right value is beeing transported into the the final function: For instance:
public void SaveAutoLogIn(bool autologindone)
{
mPrefsEditor.PutBoolean(AUTOLOGIN, autologindone);
mPrefsEditor.Commit();
}
But after retrieving a value from the function I never get was has been set to it. I know, this is a complicated problem - but I really need your guys help. I hope you can help me! Thanks a lot!
the class i want to test is posted below in the code section. I am trying to test the "setSubscriberName" method.
the test I coded is posted below in the testing section. but at run time the test fails
please let me know how to test that setter method correctly
code
public class ListViewModel {
private String mSubscriberName = null;
public ListViewModel(String subscriberName) {
mSubscriberName = subscriberName;
}
public void setSubscriberName(String name) {
mSubscriberName = name;
}
}
testing:
public class ListViewModelTest {
#Mock
private ListViewModel mListViewModel = null;
#Rule
public MockitoRule mockitoRule = MockitoJUnit.rule();
#Before
public void setUp() throws Exception {
mListViewModel = new ListViewModel("");
}
public void setSubscriberName(String str) {
String mSubscriberName = null;
mSubscriberName = str;
}
#Test
public void setSubscriberNameTest() throws Exception {
ListViewModel spyListView = spy(mListViewModel);
verify(spyListView).setSubscriberName("abc");
}
}
Looking at this example: https://github.com/googlesamples/android-architecture-components/tree/master/GithubBrowserSample
I've implemented the same pattern in one of my side projects however, I'm facing difficulties getting tests to work as expected.
I'm trying to test my one of my repository classes. The test checks if the repository fetches data from the api and if the value of the observer changes.
Here is the test class
#RunWith(JUnit4.class)
public class TimelineRepositoryTest {
private SharedPreferences sharedPreferences;
private DatabaseDao databaseDao;
private ApiService apiService;
private TimelineRepository timelineRepository;
#Rule
public InstantTaskExecutorRule instantExecutorRule = new InstantTaskExecutorRule();
#Before
public void setup() {
sharedPreferences = mock(SharedPreferences.class);
databaseDao = mock(DatabaseDao.class);
apiService = mock(ApiService.class);
timelineRepository = new TimelineRepository(apiService, sharedPreferences, databaseDao);
timelineRepository.appExecutors = new InstantAppExecutors();
}
#Test
public void fetchTimelineWithForceFetch() {
TimelineResponse timelineResponse = new TimelineResponse();
when(sharedPreferences.getLong(PreferenceUtils.PREFERENCE_LAST_TIMELINE_REFRESH, 0)).thenReturn(0L);
when(apiService.retrieveTimeline()).thenReturn(ApiUtil.successCall(timelineResponse));
MutableLiveData<List<Event>> dbData = new MutableLiveData<>();
when(databaseDao.loadEvents()).thenReturn(dbData);
Observer observer = mock(Observer.class);
timelineRepository.getTimelineEvents().observeForever(observer);
verify(observer).onChanged(Resource.loading(null));
verify(observer).onChanged(Resource.success(new ArrayList<Event>());
}
}
Also, here is the actual repository class:
public class TimelineRepository {
#Inject AppExecutors appExecutors;
#Inject #Named("timelineRefreshDurationInMillis") long timelineRefreshDurationInMillis;
private final DatabaseDao databaseDao;
private final SharedPreferences sharedPreferences;
private final ApiService apiService;
public TimelineRepository(ApiService apiService, SharedPreferences sharedPreferences, DatabaseDao databaseDao) {
this.apiService = apiService;
this.sharedPreferences = sharedPreferences;
this.databaseDao = databaseDao;
}
public LiveData<Resource<List<Event>>> getTimelineEvents() {
return new NetworkBoundResource<List<Event>, TimelineResponse>(appExecutors) {
#Override
protected void saveCallResult(#NonNull TimelineResponse timelineResponse) {
if (timelineResponse.events != null) {
databaseDao.saveEvents(timelineResponse.events);
}
PreferenceUtils.storeLastTimelineRefreshTimeInMillis(sharedPreferences, System.currentTimeMillis());
}
#Override
protected boolean shouldFetch(#Nullable List<Event> data) {
return System.currentTimeMillis() - PreferenceUtils.getLastTimelineRefreshTimeInMillis(sharedPreferences) > timelineRefreshDurationInMillis;
}
#NonNull
#Override
protected LiveData<List<Event>> loadFromDb() {
return databaseDao.loadEvents();
}
#NonNull
#Override
protected LiveData<ApiResponse<TimelineResponse>> createCall() {
return apiService.retrieveTimeline();
}
}.getAsLiveData();
}
}
I want to use the test to check if the mocked observer is called multiple times with different values. However, the test says that it is only called one with the loading argument.
After some debugging it seems like the NetworkBoundResource's https://github.com/googlesamples/android-architecture-components/blob/master/GithubBrowserSample/app/src/main/java/com/android/example/github/repository/NetworkBoundResource.java#L48 observer registered in the constructor is not called.
Has anyone faced this issue?
I have written 2 test cases which will test 2 functions of a class which does similar kind of functiomality.
This is my PrefHelper class in project:
public String getID() {
if(ID==null) {
ID = sharedpreferences.getString(_ID, null);
}
return ID ;
}
public void setID(String ID ) {
prefsEditor.putString(_ID,ID );
prefsEditor.apply();
this.ID = ID ;
}
public String getApiBasePath() {
if(apiBasePath==null) {
apiBasePath = sharedpreferences.getString(API_BASE_PATH, null);
}
return apiBasePath;
}
public void setApiBasePath(String apiBasePath) {
prefsEditor.putString(API_BASE_PATH,apiBasePath);
prefsEditor.apply();
this.apiBasePath = apiBasePath;
}
And following is my test class:
#Mock
Context context;
#Mock
SharedPreferences sharedPreferences;
#Mock
SharedPreferences.Editor editor;
private PrefsHelper prefsHelper;
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
when(context.getSharedPreferences(anyString(),anyInt())).thenReturn(sharedPreferences);
when(sharedPreferences.edit()).thenReturn(editor);
when(sharedPreferences.getString(anyString(),isNull(String.class))).thenReturn(null);
when(editor.putString(anyString(),anyString())).thenReturn(editor);
prefsHelper = PrefsHelper.getInstance(context);
}
#Test
public void apiBasePathTest(){
String returnNull=prefsHelper.getApiBasePath();
verify(sharedPreferences,times(1)).getString(anyString(),isNull(String.class));
assertEquals(null,returnNull);
doNothing().when(editor).apply();
final ArgumentCaptor<String> stringsCaptor =
ArgumentCaptor.forClass(String.class);
prefsHelper.setApiBasePath("basePath");
verify(editor,times(1)).putString(anyString(),stringsCaptor.capture());
verify(editor,times(1)).apply();
assertEquals("basePath", stringsCaptor.getAllValues().get(0));
String returnNonNull=prefsHelper.getApiBasePath();
verify(sharedPreferences,times(1)).getString(anyString(),isNull(String.class));
assertEquals("basePath",returnNonNull);
}
#Test
public void IDTest(){
String returnNull=prefsHelper.getID();
assertEquals(null,returnNull);
verify(sharedPreferences,times(1)).getString(anyString(),isNull(String.class));
doNothing().when(editor).apply();
final ArgumentCaptor<String> stringsCaptor =
ArgumentCaptor.forClass(String.class);
prefsHelper.setID("ID");
verify(editor,times(1)).putString(anyString(),stringsCaptor.capture());
verify(editor,times(1)).apply();
assertEquals("ID", stringsCaptor.getAllValues().get(0));
String returnNonNull=prefsHelper.getID();
verify(sharedPreferences,times(1)).getString(anyString(),isNull(String.class));
assertEquals("ID",returnNonNull);
}
First test case runs fine, it fails in second test at all the verify method. Its assert true works fine but verify fails in all cases and I get the below error:
Wanted but not invoked:
sharedPreferences.getString(<any>, isNull());
-> at PrefsHelperTest.IDTest
Actually, there were zero interactions with this mock. I am surprised that it works fine on first test but fails on second, where both test are doing similar functionality.
I recently converted my application from using async tasks to rxjava. Now, my espresso tests no longer wait for my data calls to complete due to espresso not having an idling resources for rxjava. I noticed that you can make custom idling resources but I can't figure out how to make it work with rxJava Schedulers, Scheduler.io specifically. Any help/best practice would be greatly appreciated.
Here is how I solved the problem:
IdlingResource implementation:
public class IdlingApiServiceWrapper implements MyRestService, IdlingResource {
private final MyRestService api;
private final AtomicInteger counter;
private final List<ResourceCallback> callbacks;
public IdlingApiServiceWrapper(MyRestService api) {
this.api = api;
this.callbacks = new ArrayList<>();
this.counter = new AtomicInteger(0);
}
public Observable<MyData> loadData(){
counter.incrementAndGet();
return api.loadData().finallyDo(new Action0() {
#Override
public void call() {
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
counter.decrementAndGet();
notifyIdle();
}
});
}
});
}
#Override public String getName() {
return this.getClass().getName();
}
#Override public boolean isIdleNow() {
return counter.get() == 0;
}
#Override public void registerIdleTransitionCallback(ResourceCallback resourceCallback) {
callbacks.add(resourceCallback);
}
private void notifyIdle() {
if (counter.get() == 0) {
for (ResourceCallback cb : callbacks) {
cb.onTransitionToIdle();
}
}
}
}
and here is my test:
public class MyActivityTest extends ActivityInstrumentationTestCase2<MyActivity> {
#Inject
IdlingApiServiceWrapper idlingApiWrapper;
#Override
public void setUp() throws Exception {
//object graph creation
super.setUp();
getActivity();
Espresso.registerIdlingResources(idlingApiWrapper);
}
public void testClickOpenFirstSavedOffer() throws Exception {
onData(is(instanceOf(DataItem.class)))
.atPosition(0)
.perform(click());
}
}
I used Dagger for dependency injection.
Wrote a little integration piece between RxJava Plugins and Espresso. Hope this helps someone else.
https://gist.github.com/digitalbuddha/d886eae1578bca78b9bf
Edit:
There is a much easier way to accomplish this task. Add the following rule to your tests
public class AsyncTaskSchedulerRule implements TestRule {
final Scheduler asyncTaskScheduler = Schedulers.from(AsyncTask.THREAD_POOL_EXECUTOR);
#Override
public Statement apply(Statement base, Description description) {
return new Statement() {
#Override
public void evaluate() throws Throwable {
RxJavaHooks.setOnIOScheduler(scheduler -> asyncTaskScheduler);
RxJavaHooks.setOnComputationScheduler(scheduler -> asyncTaskScheduler);
RxJavaHooks.setOnNewThreadScheduler(scheduler -> asyncTaskScheduler);
try {
base.evaluate();
} finally {
RxJavaHooks.reset();
}
}
};
}
}
I am currently using this implementation. Its easier and works very well for me so far: https://github.com/rosshambrick/RxEspresso