Mocked method doesn't return expected value - android

I want to test a method of my class using Mockito.
public class SplashPresenter {
public volatile State mField1 = State.DEFAULT;
public volatile State mField2 = State.DEFAULT;
boolean stateFlagsAreAllCompleted(#NonNull final ISplashView view) {
if (mField1 == State.COMPLETE //
&& mField2 == State.COMPLETE) {
// Check Forced Update
final int updateCheckResult = checkForcedUpdate(); // <===
if (updateCheckResult == MyConstants.PRODUCTION_UPDATE_AVAILABLE) {
view.displayForcedUpdateAlert(false);
return true;
}
if (updateCheckResult == MyConstants.BETA_UPDATE_AVAILABLE) {
view.displayForcedUpdateAlert(true);
return true;
}
view.restartLoader();
// Move to the home screen
return true;
}
return false;
}
int checkForcedUpdate() {
...... // my codes
}
}
and this is my test class:
public class SplashPresenterTest_ForStateFlags {
private Context mContext;
private ISplashView mView;
#Before
public void setUp() throws Exception {
mContext = Mockito.mock(Context.class);
mView = Mockito.mock(ISplashView.class);
}
#Test
public void stateFlagsAreAllCompleted() throws Exception {
SplashPresenter presenter = Mockito.mock(SplashPresenter.class);
presenter.mField1 = State.COMPLETE;
presenter.mField2 = State.COMPLETE;
when(presenter.checkForcedUpdate()).thenReturn(1);
boolean actual = presenter.stateFlagsAreAllCompleted(mView);
System.out.println("actual: " + actual + ", " +
presenter.mField1 + ", " +
presenter.checkForcedUpdate());
assertTrue(actual);
}
}
Test failure is what happens at the end. This is the output:
actual: false, COMPLETE, 1
The thing that I don't understand is even I change the stateFlagsAreAllCompleted method to following code then still test fails with above output.
boolean stateFlagsAreAllCompleted(#NonNull final ISplashView view) {
return true;
}

You've not yet mocked the behavior for the method stateFlagsAreAllComplete. You need to do:
when(presenter.stateFlagsAreAllComplete(Matchers.any()).thenReturn(true);
You can fine tune the Matchers.any() argument to the class type you want.
EDIT: I see that you are trying the test the method stateFlagsAreAllComplete. Since you are trying to test the method stateFlagsAreAllComplete of the class SplashPresenter, you cannot do so by mocking the class whose method is under test. You will have to work with an instance of the class. Mocked methods should only be used while testing when they are called in another method under test.
You will have to create an instance of the class you want to test.

Related

Android observe data not being called

Hi I am new to android development and am trying to get my head around the architecture but have spent the past 2 days trying to figure out LiveData
I am using an SDK which allows me to scan some sensors, I display the sensors on the device and then toggle a switch to connect the sensor. Once the sensor is connected I have created a button which runs a funcion called startMeasuring() everytime some data is measured a callback is hit and this is where my struggle begins.
In my MainActivity I have the following code which is ran once I toggle the switch to connect to the sensor.
public void onConnectedSensorClick(BluetoothDevice sensor, Integer position, Boolean checked) {
XsensDotDevice xsDevice = new XsensDotDevice(this, sensor, new XsDevice(this));
if (checked) {
xsDevice.connect();
mMainActivityViewModel.addConnectedSensor(xsDevice);
}
}
The XsensDotDevice() expects 3 parameters the context, scanned sensor and the callback class.
In my callback calss the following callback function is overridden
#Override
public void onXsensDotDataChanged(String s, XsensDotData xsensDotData) {
}
This function is the one which gets triggered when I start measuring and the sensor sends the device a measurement.
I am have created a ViewModel and Repository which is what I want to use to store this data so I can access it back in my MainActivity using an Observer
I got the ViewModel and Repository working for my scanned devices but I'm not sure how to get this working for the measurement data because I can't access the ViewModel in my callback class XsDevice() to pass the data to the Repository
What I want to do is somehow pass the XsensDotData (measurement data) to the SensorDataRepository and then create an Observer in my MainActivity like so.
mMainActivityViewModel.getSensorData().observe(this, new Observer<XsensDotData>() {
#Override
public void onChanged(XsensDotData xsensDotData) {
for(int i = 0; i< xsensDotData.getFreeAcc().length; i++){
Log.d("Sensor Data Acceleration " + i, String.valueOf(xsensDotData.getFreeAcc()[i]));
}
}
});
I have already created a Repository and ViewModel which i will show below
Repository
public class SensorDataRepository {
private static SensorDataRepository instance;
private XsensDotData dataSet = new XsensDotData();
public static SensorDataRepository getInstance() {
if (instance == null) {
instance = new SensorDataRepository();
}
return instance;
}
public MutableLiveData<XsensDotData> getSensorData() {
MutableLiveData<XsensDotData> data = new MutableLiveData<>();
data.setValue(dataSet);
return data;
}
public void addSensorData(XsensDotData data) {
dataSet = data;
}
}
ViewModel
public class MainActivityViewModel extends ViewModel {
private MutableLiveData<ArrayList<BluetoothDevice>> mScannedSensors;
private ScannedSensorRepository mScannedSensorRepo;
private MutableLiveData<ArrayList<XsensDotDevice>> mConnectedSensors;
private ConnectedSensorRepository mConnectedSensorRepo;
private MutableLiveData<XsensDotData> mSensorData;
private SensorDataRepository mSensorDataRepo;
public void init() {
if (mScannedSensors != null) {
return;
}
mScannedSensorRepo = ScannedSensorRepository.getInstance();
mScannedSensors = mScannedSensorRepo.getScannedSensors();
if (mConnectedSensorRepo != null) {
return;
}
mConnectedSensorRepo = ConnectedSensorRepository.getInstance();
mConnectedSensors = mConnectedSensorRepo.getConnectedSensors();
if (mSensorDataRepo != null) {
return;
}
mSensorDataRepo = SensorDataRepository.getInstance();
mSensorData = mSensorDataRepo.getSensorData();
}
public LiveData<ArrayList<BluetoothDevice>> getScannedSensors() {
return mScannedSensors;
}
public void addScannedSensor(BluetoothDevice device) {
mScannedSensorRepo.addScannedSensors(device);
}
public LiveData<ArrayList<XsensDotDevice>> getConnectedSensors() {
return mConnectedSensors;
}
public void addConnectedSensor(XsensDotDevice device) {
mConnectedSensorRepo.addConnectedSensors(device);
}
public LiveData<XsensDotData> getSensorData() {
return mSensorData;
}
public void addSensorData(XsensDotData data) {
mSensorDataRepo.addSensorData(data);
}
}
I included the code for the scanned and connect devices in the ViewModel in case it come in handy and helps explain whats going on.
Thank you for any help!
Here is a simple example of how I use LiveData. In my view model I will have a value as so :
var isInternetAvailable = MutableLiveData<Boolean>().apply { value = true }
in my activity I will have the code:
viewmodel.isInternetAvailable.observe(this, Observer {
// execute your logic here
var theValue = viewmodel.isInternetAvailable.value!!
}
Then in my viewModel when the internet has changed I will use
viewmodel.isInternetAvailable.postValue(true)
So for your code - as far as I can see, you're observing the function but not posting to it in order to trigger your observer function
You can use
MutableLiveData<XsensDotData> data = new MutableLiveData<>();
and then
data.postValue(dataSet)
That should hopefully trigger your observer

Mockito does not return mockValue when mockito class passed as a dependency

It is a bit tough the explain the situation actually. I mock a class and pass it to another class's constructor. Then, I create the first class and call the first class's method under the second class's method, it returns null. Please check below:
class A {
public String getName() {
return "Something";
}
}
class B {
private A a;
public B(A insA) {
this.a = insA;
}
public String createName() {
return a.getName(); // when this is called, returns null.
}
}
class TestB {
public testBSomething() {
A mockA = mock(A.class);
when(mockA.getName()).thenReturn("Somevalue");
B insB = new B(mockA);
assertEqual("SomeValue", insB.createName()); // insB.createName() = null which should return "Somevalue"
}
}
I also tried doReturn, thenAnswer and spy variations, but no luck. Probably, I miss something, but I could not find. If anyone has any idea, I will really appreciate it. Thank you.
Here,
#RunWith(MockitoJUnitRunner.class)
public class TestB {
#Mock
A mockA;
#InjectMocks
B insB;
#Before
public void setup() {
insB = new B(mockA);
}
#Test
public void testBSomething() {
when(mockA.getName()).thenReturn("SomeValue");
Assert.assertEquals("SomeValue", insB.createName());
}
}

Final boolean is changing value

I have a class variable that is final and is set in the constructor. When I check the value of it in the constructor for the abstract class and the subclass it's the correct value. But when I check it later in a method it's always false. Here's my code.
abstract class AbstractArticleObject extends StructureObject {
final boolean firstArticle;
AbstractArticleObject(Element element, boolean firstArticle) {
super(element);
this.firstArticle = firstArticle;
...
}
}
class ArticleObject extends AbstractArticleObject {
ArticleObject(Element element, boolean firstArticle) {
super(element, firstArticle);
// In this method, firstArticle is whatever was passed in, which is sometimes true.
Log.v(title, String.format(String.valueOf(this.firstArticle));
}
#Override
StructureState getState() {
// In this method, firstArticle is always false.
Log.v(title, String.format(String.valueOf(firstArticle));
if (...) {
...
} else if (...) {
if (firstArticle) {
return StructureState.CAN_OPEN;
} else {
...
}
}
return StructureState.NOT_SET;
}
}
If I'm setting the value in the constructor, and the value is final, why is it returning false even when it was set to true?
Where is getState() called from?
It is possible for final variables to "change" if you access them before they're ever initialized. Consider the following tiny program:
public class Test {
private final boolean value;
public Test() {
doSomething();
this.value = true;
doSomething();
}
private void doSomething() {
System.out.println(value);
}
public static void main(String[] args) {
new Test();
}
}
The output of this program will be
false
true
So, if your getState() method is called from e.g. the constructor of StructureObject, then it will be called before the AbstractArticleObject constructor initializes firstArticle, and it will be false.

Android RecyclerView Adapter Item count is returning 0 on unit testing

I am trying to test RecyclerView with AndroidJunit4, it is my test code:
#Rule
public ActivityTestRule<ProductListActivity> rule = new ActivityTestRule<>(ProductListActivity.class);
............................
..........................
#Test
public void ensureDataIsLoadingOnSuccess() throws Exception {
ProductListActivity activity = rule.getActivity();
...........................
............
activity.runOnUiThread(new Runnable() {
public void run() {
activity.displayProducts(asList(product1, product2), 0);
}
});
assertEquals(2, mAdapter.getItemCount());
assertThat(((ProductAdapter) mAdapter).getItemAtPosition(0),sameInstance(product1));
assertThat(((ProductAdapter) mAdapter).getItemAtPosition(1),sameInstance(product2));
}
Here is my code for displayProducts() in Activity:
#Override
public void displayProducts(List<Product> products, Integer pageNo) {
progressBar.setVisibility(View.GONE);
if (pageNo == 0 && products.size() == 0) {
noProductTextView.setVisibility(View.VISIBLE);
} else {
mProductAdapter.addProduct(products);
noProductTextView.setVisibility(View.GONE);
productListView.setVisibility(View.VISIBLE);
}
}
It is giving error like:
junit.framework.AssertionFailedError: expected:<2> but was:<0>
at junit.framework.Assert.fail(Assert.java:50)
at junit.framework.Assert.failNotEquals(Assert.java:287)
at junit.framework.Assert.assertEquals(Assert.java:67)
at junit.framework.Assert.assertEquals(Assert.java:199)
at junit.framework.Assert.assertEquals(Assert.java:205)
at com.kaushik.myredmart.ui.ProductListActivityTest.ensureDataIsLoadingOnSuccess(ProductListActivityTest.java:94)
Please help what is the problem in my code?
The reason is that your Espresso test did not wait your loading task which is time-consuming.
You need to use a espresso-idling-resource to tell it to wait this task to finish.
Then you need a class to implement IdlingResource and declare it your Activity.
When your Espresso test run, it will know and wait your long-time consuming task to complete and test the result.
Firstly, add its dependency.
compile "com.android.support.test.espresso:espresso-idling-resource:2.2.2"
Secondly, you need two Java files in folder src/main/java/your-package.
SimpleCountingIdlingResource.java
public final class SimpleCountingIdlingResource implements IdlingResource {
private final String mResourceName;
private final AtomicInteger counter = new AtomicInteger(0);
// written from main thread, read from any thread.
private volatile ResourceCallback resourceCallback;
/**
* Creates a SimpleCountingIdlingResource
*
* #param resourceName the resource name this resource should report to Espresso.
*/
public SimpleCountingIdlingResource(String resourceName) {
mResourceName = checkNotNull(resourceName);
}
#Override public String getName() {
return mResourceName;
}
#Override public boolean isIdleNow() {
return counter.get() == 0;
}
#Override public void registerIdleTransitionCallback(ResourceCallback resourceCallback) {
this.resourceCallback = resourceCallback;
}
/**
* Increments the count of in-flight transactions to the resource being monitored.
*/
public void increment() {
counter.getAndIncrement();
}
/**
* Decrements the count of in-flight transactions to the resource being monitored.
*
* If this operation results in the counter falling below 0 - an exception is raised.
*
* #throws IllegalStateException if the counter is below 0.
*/
public void decrement() {
int counterVal = counter.decrementAndGet();
if (counterVal == 0) {
// we've gone from non-zero to zero. That means we're idle now! Tell espresso.
if (null != resourceCallback) {
resourceCallback.onTransitionToIdle();
}
}
if (counterVal < 0) {
throw new IllegalArgumentException("Counter has been corrupted!");
}
}
}
EspressoIdlingResource.java
public class EspressoIdlingResource {
private static final String RESOURCE = "GLOBAL";
private static SimpleCountingIdlingResource mCountingIdlingResource =
new SimpleCountingIdlingResource(RESOURCE);
public static void increment() {
mCountingIdlingResource.increment();
}
public static void decrement() {
mCountingIdlingResource.decrement();
}
public static IdlingResource getIdlingResource() {
return mCountingIdlingResource;
}
}
Ok. Let's go to Activity where you have a time-consuming task.
Firstly, put this method at the bottom.
#VisibleForTesting
public IdlingResource getCountingIdlingResource() {
return EspressoIdlingResource.getIdlingResource();
}
Inside your time-consuming task. you should tell your Espresso to wait like this.
EspressoIdlingResource.increment();
yourTask.run(new Callback() {
void onFinish(){
EspressoIdlingResource.decrement();
}
})
Final step is to define these methods in your UI test class.
#Before
public void registerIdlingResource() {
Espresso.registerIdlingResources(mOnBoardActivityTestRule.getActivity().getCountingIdlingResource());
}
/**
* Unregisters your idling resource so it can be garbage collected and does not leak any memory
*/
#After
public void unregisterIdlingResource() {
Espresso.unregisterIdlingResources(mOnBoardActivityTestRule.getActivity().getCountingIdlingResource());
}
Yeah. Finally we done.
There is one problem I can see here, your are inquiring the List size before the Main/UI thread is able to update it. So, you will have to wait in the current thread till the Activity finished updating the list on Main thread.
You can do,
Thread.sleep(500);
in the Test class to wait, to test the list setting behavior in Activity and you will find the assertion to be valid.
Since, the main thread runs infinitely till the application is running, you will have to implement a callback interface provided by the Activity to be informed about when populating the list is finished.

Using Espresso idling resource with multiple activities

I have a firstActivity that launches the secondActivity, where in the secondActivity I have a loading Dialog (not AsyncTask), and I need to make Espresso wait until the dialog disappears before it continues with the test.
Where do I have to implement the IdlingResource? How can I make it wait for the dismissDialog() function?
Here is what I've tried to do:
class DocumentLoadingIdlingResource implements IdlingResource {
private ResourceCallback callback;
#Override
public String getName() {
return "Documnet loading idling resource";
}
#Override
public boolean isIdleNow() {
Activity activity;
try {
activity = getCurrentActivity();
} catch (Throwable e) {
return false;
}
if(activity.getClass().getName().equals(EditorActivity.class.getName())
&& activity.loadingDialogShowing() == false) {
return false;
}
return true;
}
#Override
public void registerIdleTransitionCallback(ResourceCallback callback) {
this.callback = callback;
}
}
Activity getCurrentActivity() throws Throwable {
getInstrumentation().waitForIdleSync();
final Activity[] activity = new Activity[1];
runTestOnUiThread(new Runnable() {
#Override
public void run() {
java.util.Collection<Activity> activites = ActivityLifecycleMonitorRegistry.getInstance().getActivitiesInStage(Stage.RESUMED);
activity[0] = com.google.common.collect.Iterables.getOnlyElement(activites);
}});
return activity[0];
}
This class is implemented in the test class.
There are a few problems here:
Your isIdleNow() calls getCurrentActivity() which calls waitForIdleSync() and runTestOnUiThread(). isIdleNow Javadoc says: "Espresso will always call this method from the main thread, therefore it should be non-blocking and return immediately." So this won't work as is, but you could call getActivitiesInStage directly from isIdleNow.
Your other issue is that you store the reference to ResourceCallback but never invoke onTransitionToIdle, also you should allow for the possibility of more than one ResourceCallback being registered and call onTransitionToIdle on all of the callbacks.
You can do the following:
Copy/Paste IdlingResource into your app as com.mycompany.IdlingResource.
Then have your Activity implement that interface and make sure to call onTransitionToIdle when the dialog goes away and make sure isIdleNow returns false iff the dialog is showing.
In your test code, write a "IdlingResourceAdapter" that wraps com.mycompany.IdlingResource and turns it into an Espresso IdlingResource and register that with Espresso.
This will be simpler once this issue is implemented: https://code.google.com/p/android-test-kit/issues/detail?id=71
I stumbled upon this question in my search for a similar answer. Using concepts from Stefano Dacchille's article on IdlingResources, I built the following idling resource that waits for a specific Activity to be active before firing. In my case, I know the dialog is showing when a fragment with a specific tag exists. This isn't the same as the OP's test, but the concepts should translate well.
public class BusyWhenFragmentExistsInActivityIdlingResource implements IdlingResource {
private FragmentActivity activity = null;
private final String fragmentTag;
private ResourceCallback resourceCallback;
private boolean wasIdleLastTime = true; // Start off as idle
private final String name;
// Need this strong reference because ActivityLifecycleMonitorRegistry won't hold one
private final ActivityLifecycleCallback activityLifecycleCallback;
public BusyWhenFragmentExistsInActivityIdlingResource(
final Class<? extends FragmentActivity> clazz,
final String fragmentTag
){
name = BusyWhenFragmentExistsInActivityIdlingResource.class.getSimpleName()+" "+clazz.getSimpleName();
this.fragmentTag = fragmentTag;
activityLifecycleCallback = new ActivityLifecycleCallback() {
#Override
public void onActivityLifecycleChanged(Activity activity, Stage stage) {
if (!FragmentActivity.class.isAssignableFrom(activity.getClass())) {
return;
}
FragmentActivity fragmentActivity = (FragmentActivity) activity;
if (!clazz.isAssignableFrom(fragmentActivity.getClass())) {
return;
}
switch (stage){
case RESUMED:
BusyWhenFragmentExistsInActivityIdlingResource.this.activity = fragmentActivity;
break;
case STOPPED:
BusyWhenFragmentExistsInActivityIdlingResource.this.activity = null;
break;
}
}
};
ActivityLifecycleMonitorRegistry.getInstance()
.addLifecycleCallback(activityLifecycleCallback);
}
#Override
public String getName() {
return name;
}
#Override
public boolean isIdleNow() {
if (activity==null) {
return wasIdleLastTime = true;
}
boolean isIdleThisTime = activity
.getSupportFragmentManager()
.findFragmentByTag(fragmentTag)==null;
if (!wasIdleLastTime && isIdleThisTime && resourceCallback!=null){
resourceCallback.onTransitionToIdle();
}
return wasIdleLastTime = isIdleThisTime;
}
#Override
public void registerIdleTransitionCallback(ResourceCallback resourceCallback) {
this.resourceCallback = resourceCallback;
}
}
To use it, add something similar to this to your test:
#Before
public void setUp() throws Exception {
registerIdlingResources(new BusyWhenFragmentExistsInActivityIdlingResource(
SomeOtherActivity.class,
BaseActivity.LOADING_DIALOG
));
}

Categories

Resources