In my android project, In my presenter, I'm running one background thread in a Runnable anonymous class which applies changes in presenter class member. When the thread ends it calls a callback.
Does anyone have an example of Runnable anonymous class mocking that applies changes in the Outer class?
I was short on time so I couldn't publish my code. To answer my question I had to refactor my code and reduce the coupling between classes.
So, let me show you the conflictive part:
#Override
public void onResponse(final PresentationModel presentationModel) {
presentationModelWrapper.clear();
presentationModelWrapper.add(presentationModel);
if(isViewAttached()){
final SomeHandler someHandler = view.getSomeHandler();
someHandler.execute(new Runnable() {
#Override
public void run() {
//some code here
}
});
}
}
When the execution of someHandler ends I call the callback function which call a method of the presenter. Now, let me show you my solution:
#Mock
private SomeContract.View view;
#Mock
private SomeHandler someHandler;
#Captor
private ArgumentCaptor<SomeCallback> somethingCallbackArgumentCaptor;
#InjectMocks
private SomePresenter presenter;
#Test
public void loadSomething_shouldShowSomething() {
// Given
Map<String, String> parameters = new HashMap<String, String>();
parameters.put(Constant.API_PARAMETER_QUERY, CUSTOM_QUERY);
// Given a stubbed model
model = new PresentationModel();
//when
presenter.loadSomething(parameters);
//This part mock the someInteractor call
when(view.getSomeHandler()).thenReturn(someHandler);
verify(someInteractor).execute(anyMap(), somethingCallbackArgumentCaptor.capture());
somethingCallbackArgumentCaptor.getValue().onResponse(model);
//we are on response my conflictive part
verify(someHandler).execute(any(Runnable.class));
//I use presenter instead of ArgumentCaptor because handler has a presenter reference
presenter.onDatabaseOperationFinished();
// Then
SomethingUI uiModel = presenter.getUiModel();
verify(view).showSomething(uiModel);
}
Related
I'm using multiple MutableLiveData on an MVVM architecture.
on the ViewModel, I post the objects but the fragment is not resumed.
when the fragment has resumed the observers get the MutableLiveData but not in the order I post them.
How can I force an order of getting the MutableLiveData?
ViewModel:
void foo(){
first_MutableLiveData.post(newData)
second_MutableLiveData.post(newData)
}
fragment:
initView(){
first_MutableLiveData.observe(this,()->{
"getting called second"})
second_MutableLiveData.observe(this,()->{
"getting called first"})
}
You can't force what you want. As you can see from the code they are posting the result to the MainThread by calling:
ArchTaskExecutor.getInstance()
So now one would bother to support the syncronization between two different LiveData objects. It is your job do do so. It is a corner case.
Just use setValue, instead of postValue directly on the MainThread. Here is an example.
public class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
#Override
public void execute(Runnable runnable) {
handler.post(runnable);
}
}
public class YourClass {
MutableLiveData first_MutableLiveData = new MutableLiveData<Data>();
MutableLiveData second_MutableLiveData = new MutableLiveData<Data>();
private final Executor executor;
public YourClass(Executor executor) {
this.executor = executor;
}
void foo(){
executor.execute(new Runnable(){
#Override
public void run() {
first_MutableLiveData.setValue(newData);
second_MutableLiveData.setValue(newData);
}
});
}
}
So apparently when I changed the observer's order on the fragment they arrived in the order I needed them to be. Thanks everyone for the quick response!
I would like to create a CountdownTimer which will trigger events that will update the UI (trigger popup, start an animation, etc.).
I wonder how to do this clean, here are my hypothesis and why :
A separate component EventCountdownTimer. I could then benefit the use of LifecycleObserver, but I wonder how to communicate the information back to the activity (I tried extending CountdownTimer and using it in the activity but I have an error and can't get it to compile)
In the Activity itself, it's the simplest but I'm not sure it belongs there as it isn't a UI component and I can't benefit the LifecycleObserver
In the ViewModel. I thought as it's activity related and the CountdownTimer is kinda logic data, it should go in here, but that means also watching the lifecycle of the activity, and holding any Activity related field within ViewModel is bad practice.
What's the best option according to you? And why?
In a MVVM pattern you could have a LiveData observable in your ViewModel which will be observed by the UI and upon value change you update the UI accordingly. How that observable changes value, that is your business logic and all of it should be in your ViewModel or in separate components that will be used by the ViewModel to update the observable state.
This will allow you to separate the UI from the business logic being your observable the bridge of communication between both, without the ViewModel having any knowledge of whats going on in the UI. In simple words it only executes what it is told to execute and updates a variable that is being observed, what then happens in the UI is the UI responsibility and with this you have reached a clear separation of concerns.
A separate component "EventCountdownTimer"
In my opinion, this is the best implementation that you might have in your case. For communicating information back to your activity, you might consider having an interface like the following.
public interface TimerListener {
void onTimerResponse(String response);
}
Modify your EventCountdownTimer to have a constructor which takes TimerListener as a parameter and override the onTimerResponse method in your activity. Now from your EventCountdownTimer, when you are trying to communicate with your activity along with a message, for example, you might just call the function onTimerResponse(msgToDeliver).
Hence your EventCountdownTimer should look something like this.
public class EventCountdownTimer {
public static Context context;
public static TimerListener listener;
public EventCountdownTimer(Context context, TimerListener listener) {
this.context = context;
this.listener = listener;
}
public startCountdown() {
// Start the count down here
// ... Other code
// When its time to post some update to your activity
listener.onTimerResponse(msgToDeliver);
}
}
And from your activity, initialize the EventCountdownTimer like the following.
EventCountdownTimer timer = new EventCountdownTimer(this, new TimerListener() {
#Override
public void onTimerResponse(String message) {
// Do something with the message data
// Update your UI maybe
}
});
I think you have provided good reasons already for not going for other options that you have mentioned.
Google solution : see it on github
/**
* A ViewModel used for the {#link ChronoActivity3}.
*/
public class LiveDataTimerViewModel extends ViewModel {
private static final int ONE_SECOND = 1000;
private MutableLiveData<Long> mElapsedTime = new MutableLiveData<>();
private long mInitialTime;
private final Timer timer;
public LiveDataTimerViewModel() {
mInitialTime = SystemClock.elapsedRealtime();
timer = new Timer();
// Update the elapsed time every second.
timer.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
final long newValue = (SystemClock.elapsedRealtime() - mInitialTime) / 1000;
// setValue() cannot be called from a background thread so post to main thread.
mElapsedTime.postValue(newValue);
}
}, ONE_SECOND, ONE_SECOND);
}
public LiveData<Long> getElapsedTime() {
return mElapsedTime;
}
#Override
protected void onCleared() {
super.onCleared();
timer.cancel();
}
}
I am testing with Mockito. I Have a callback interface:
interface Callback {
void onMessageRetrieved(String message);
void onRetrievalFailed(String error);
}
Then, I have a method that accepts Runnable object that calls that Callback method:
Firstly, interactor.run() calls this method that calls postMessage:
#Override
public void run() {
final String message = mMessageRepository.getWelcomeMessage();
if (message == null || message.length() == 0) {
notifyError();
return;
}
postMessage(message);
}
private void postMessage(final String msg) {
mMainThread.post(new Runnable() {
#Override
public void run() {
mCallback.onMessageRetrieved(msg);
}
});
}
But line mCallback.onMessageRetrieved(msg); is never executed and so I get:
Wanted but not invoked:
callback.onMessageRetrieved(
"Welcome, friend!"
);
Why is run() not executed?
I am working with the project from this articles. This is my Test class:
public class ExampleUnitTest {
private MessageRepository mMessageRepository;
private Executor mExecutor;
private MainThreadImpl mMainThread;
private WelcomingInteractor.Callback mMockedCallback;
#Before
public void setUp() {
mMessageRepository = mock(MessageRepository.class);
mExecutor = mock(Executor.class);
mMainThread = mock(MainThreadImpl.class);
mMockedCallback = mock(WelcomingInteractor.Callback.class);
}
#Test
public void testWelcomeMessageFound() throws Exception {
String msg = "Welcome, friend!";
when(mMessageRepository.getWelcomeMessage()).thenReturn(msg);
WelcomingInteractorImpl interactor = new WelcomingInteractorImpl(
mExecutor,
mMainThread,
mMockedCallback,
mMessageRepository);
interactor.run();
Mockito.verify(mMessageRepository).getWelcomeMessage();
Mockito.verifyNoMoreInteractions(mMessageRepository);
Mockito.verify(mMockedCallback).onMessageRetrieved(msg);
}
}
Here:
mMainThread.post(new Runnable()
But in your unit test, you have:
mExecutor = mock(Executor.class);
mMainThread = mock(MainThreadImpl.class);
That post() call receives a Runnable object. And I assume that your impl class runs Runnable.run() in some thread.
But: within your unit test, you are mocking all those elements.
You have to understand: mMainThread = mock(MainThreadImpl.class); doesn't create a real MainThreadImpl object. It returns something that looks like an object of that class; but this is a mock. It is completely decoupled from your actual implementation. When you do mMainThread.poll() ... nothing will happen. That run method is never executed. Because the mock object does nothing about that parameter when you invoke poll() on it.
In other words: you have to configure all your mocks. For example you can use an ArgumentCaptor and capture the Runnable object given to the post() method.
But of course, as that will be just some instance of an anonymous inner class, this will not help too much.
Long story short: you should step back; and do some more reading how/why you use mock objects...
I am using Otto's event bus in my application. In one of my classes I am posting the event.
MyEvent myevent = new MyEvent();
uiBus.post(myEvent);
I am able to test the post method.
Now there is another class which is receiving the event.
//ReceiverClass.java
#Subscribe
public void onEventReceived(MyEvent myevent) {
callAMethod();
}
How do I unit test that this method was invoked. I tried with the following test code
#Mock
Bus uiBus;
#Test
public void testBusReceviedEvent() {
ReceiverClass instance = new ReceiverClass();
mockBus.register(instance);
MyEvent myevent = new MyEvent();
mockBus.post(myEvent);
//Test
verify(instance, times(1)).callAMethod();
}
But this code doesn't work.
I'm a little late to the party but here is an example of a class which works and accounts for async calls. Instead of Mocking EventBus we simply let it do it's thing and register it in the TestDriver class below.
The thing that makes this work is the CountDownLatch which, with the help of the abstract DataTransferCallback class, waits for latch.countDown() to be called or 5 seconds to go by.
Just register your test class and in the #Subscribe method, pass it back to the method that created the DataTransferCallback and do your assertions there.
#RunWith(AndroidJUnit4.class)
public class TestDriver {
private final CountDownLatch latch = new CountDownLatch(1);
private EventBus eventBus;
private DataTransferCallback transferCallback;
public abstract class DataTransferCallback {
abstract void onSuccess(DataTransfer event);
}
#Before
public void setUp() {
EventBus.getDefault().register(this);
eventBus = spy(EventBus.getDefault());
}
#SuppressWarnings("unchecked")
#Test
public void test200Resposne() throws InterruptedException {
// Get known good JSON
final String json = TestJSON.get200Response();
// Class under test
final Driver driver = new Driver(InstrumentationRegistry.getTargetContext());
final JsonParser jsonParser = new JsonParser();
//boolean to hold our test result
final boolean[] testPassed = new boolean[]{false};
transferCallback = new DataTransferCallback() {
#Override
public void onSuccess(DataTransfer event) {
assertNotNull(event);
verify(eventBus).post(event);
assertThat(event.getStatus(), is("OK"));
assertTrue(event.getData() != null);
testPassed[0] = true;
}
};
//Set our test EventBus object
driver.setEventBus(eventBus);
// The actual method under test
driver.parseData(jsonParser.parse(json));
// Set a countdown latch to wait for the result (5s)
latch.await(5000, TimeUnit.MILLISECONDS);
// will wait here until 5s or the #Subscrube method is hit
assertTrue(testPassed[0]);
}
//Because we want to examine EventBus Output, register it
//to this class and pass the event back through our custom abstract class
#Subscribe
public void onReceiveEventBusEvent(DataTransfer event) {
assertNotNull(transferCallback);
transferCallback.onSuccess(event);
//notify latch so that we can proceed
latch.countDown();
}
}
It does not work because instance is not a mock. You will have to verify the effects of callAMethod or put that method in another class and inject a mock of this new class into your ReceiverClass class.
For example...
private class ReceiverClass {
private MyNewClass theNewClassIWasTalkingAbout;
// Stick in a setter for that ^
#Subscribe
public void onEventReceived(MyEvent myevent) {
theNewClassIWasTalkingAbout.callAMethod();
}
}
Then your test will have to change slightly...
#Mock
private MyNewClass mockNewClass;
#InjectMocks // This will be the "solid" implementation of the thing you are trying to test, it is not a mock...
private ReceiverClass instance;
#Test
public void testBusReceivedEvent() {
mockBus.register(instance);
MyEvent myevent = new MyEvent();
mockBus.post(myevent);
verify(mockNewClass, times(1)).callAMethod();
}
Hope this helps.
In my Android project, I have a class extends HandlerThread:
public class MyHandlerThread extends HandlerThreads {
private Handler mHandler;
…
public void doAsyncTask(MyAsyncTask task) {
mHandler = new Handler(this.getLooper());
mHandler.post(task);
}
}
The above function's parameter type MyAsyncTask is a class extends Runnable:
public abstract class MyAsyncTask implements Runnable {
#Override
public void run() {
doTask();
}
public abstract void doTask();
}
I have a MyWorker class which has a function uses MyHandlerThread class:
public class MyWorker {
public void work() {
MyHandlerThread handlerThread = new MyHandlerThread();
handlerThread.start();
handlerThread.doAsyncTask(new MyAsyncTask() {
#Override
doTask() {
int responseCode = sendDataToServer();
}
});
}
}
I want to use Mockito to unit test the work() function in MyWorker class (e.g. check the server responseCode). How to do it in Mockito?
WHAT do you want to test? MyWorker? MyHandlerThread? the anonymous MyAsyncTask? All toegether? Probably a bad idea, especially if the anonymous MyAsyncTask relies on an actual server response (which would prevent this from being a good unit test, since you are testing a whole system then). So, I would split the whole thing into parts and test all these parts seperately. If you have done so, then you can check multiple parts toegether against a real server with an integration tests.
To test the MyHandlerThread, you could for example introduce a HandlerFactory, mock that and thus ensure that the handler was called correctly.
public class MyHandlerThread extends HandlerThreads {
private HandlerFactory handlerFactory; // <- Add setter
…
public void doAsyncTask(MyAsyncTask task) {
Handler mHandler = handlerFactory.createHandler(this.getLooper());
mHandler.post(task);
}
}
Easily testable unit. MyAsyncTask is short and abstract, honestly, I wouldn't test that. Not much to gain there, since it doesn't actually do much. And the MyWorker ? Depends, but you could, for example, add a getter/setter for the MyHandlerThread, allowing you to mock that. Extracting your anonymous class into a real one would probably allow you to test that one, too, independent of the others.