patternjavaMinor
Scheduling a response callback
Viewed 0 times
callbackresponsescheduling
Problem
I have an Android service which must offload a task to a different thread but schedule the response callback unto the calling thread. After much thinking I came up with this code:
```
public void testRequestingAScheduleUpdateShouldNotBlockAndDeliverItOnTheCallingThread() throws Exception {
final StreamSchedule mockSchedule = new StreamSchedule(
new StreamMetadata("TyPhone", "Tidal Waves 028"),
new StreamMetadata[] { new StreamMetadata(null, "The Progmatic Radio Show 002 with Ashley Bonsall") },
new StreamMetadata[] { new StreamMetadata("TEKNO", "Sound Escalation 065 with Xabi") }
);
final boolean[] threadBlocked = {true};
LooperThread looperThread = new LooperThread();
looperThread.start();
StreamScheduleProvider mockScheduleProvider = mock(StreamScheduleProvider.class);
when(mockScheduleProvider.getCurrentStreamSchedule()).then(invocation -> {
threadBlocked[0] = Thread.currentThread().getId() == looperThread.getId();
return mockSchedule;
});
DataAccessModule.scheduleProviderOverride = mockScheduleProvider;
final long[] callingThreadId = {-1};
ScheduleUpdateListener updateListener = mock(ScheduleUpdateListener.class);
doAnswer(invocation -> {
callingThreadId[0] = Thread.currentThread().getId();
looperThread.stopLooper();
return null;
}).when(updateListener).onScheduleChanged(any(StreamSchedule.class));
PlaybackServiceBinder serviceBinder = (PlaybackServiceBinder) bindService(getServiceIntent());
serviceBinder.subscribeScheduleUpdates(updateListener);
looperThread.getHandler().post(serviceBinder::updateSchedule);
looperThread.join();
verify(updateListener).onScheduleChanged(mockSchedule);
assertFalse("The thread was blocked, this is unacceptable", threadBlocked[0]);
assertEquals("The update callback was not called on the requesting thread", callingThreadId[0], looperThread.getId());
}
class LooperThread extends Thread
```
public void testRequestingAScheduleUpdateShouldNotBlockAndDeliverItOnTheCallingThread() throws Exception {
final StreamSchedule mockSchedule = new StreamSchedule(
new StreamMetadata("TyPhone", "Tidal Waves 028"),
new StreamMetadata[] { new StreamMetadata(null, "The Progmatic Radio Show 002 with Ashley Bonsall") },
new StreamMetadata[] { new StreamMetadata("TEKNO", "Sound Escalation 065 with Xabi") }
);
final boolean[] threadBlocked = {true};
LooperThread looperThread = new LooperThread();
looperThread.start();
StreamScheduleProvider mockScheduleProvider = mock(StreamScheduleProvider.class);
when(mockScheduleProvider.getCurrentStreamSchedule()).then(invocation -> {
threadBlocked[0] = Thread.currentThread().getId() == looperThread.getId();
return mockSchedule;
});
DataAccessModule.scheduleProviderOverride = mockScheduleProvider;
final long[] callingThreadId = {-1};
ScheduleUpdateListener updateListener = mock(ScheduleUpdateListener.class);
doAnswer(invocation -> {
callingThreadId[0] = Thread.currentThread().getId();
looperThread.stopLooper();
return null;
}).when(updateListener).onScheduleChanged(any(StreamSchedule.class));
PlaybackServiceBinder serviceBinder = (PlaybackServiceBinder) bindService(getServiceIntent());
serviceBinder.subscribeScheduleUpdates(updateListener);
looperThread.getHandler().post(serviceBinder::updateSchedule);
looperThread.join();
verify(updateListener).onScheduleChanged(mockSchedule);
assertFalse("The thread was blocked, this is unacceptable", threadBlocked[0]);
assertEquals("The update callback was not called on the requesting thread", callingThreadId[0], looperThread.getId());
}
class LooperThread extends Thread
Solution
Disclaimer: I don't know Android. I've wrote two or three programs for it.
Also, I don't have your full code so can't be sure about some of the classes this code relies on.
Also, I don't have your full code so can't be sure about some of the classes this code relies on.
- Test name has an "and", seems like two tests?
- Test throws Exception, do you have tests for that?
- You don't need to start test name with tests, unless you use JUnit 3.
- When
LooperThreadruns, it callsLooper.prepare()andLooper.loop(). What these do?
LooperThread extends Thread, why notimplement Runnable? You only implementrun()then?
- Further reinforcement to point 1) - you have more than one assertion. If
verifybuckles, other assertions aren't tested. Is that fine?
- Why do you need a
final boolean[] threadBlocked = {true};over just afinal boolean? I found no other reference than to that one element, viathreadBlocked[0]?
- Is this test alone it it's class? If so, I'd extract mocking out of it. Readability / clarity / easier to spot things.
- Have you tried structuring the test into classic given - when - then or assess - act - assert?
Context
StackExchange Code Review Q#88420, answer score: 2
Revisions (0)
No revisions yet.