What is the correct architecture design here? - java

The problem is taken from initializing and retrieving data from Firebase, however I will translate this to pseudo in order those who are not familiar could also contribue. Please consider the following code:
`
//Given the following API (from Firebase)
MyRemoteDBClass.asyncAuthenticate(initCompletedListener);
MyRemoteDBClass.asyncDataFetch(fetchCompletedListener)
// of course you have to authenticate before fetching the data
Class MyClassA.init()
{
MyRemoteDBClass myRemoteDBClassInstance = new MyRemoteDBClass();
myRemoteDBClassInstance.asyncAuthenticate(some_listener);
}
// Then somewhere in the app:
Class MyClassB.asyncDataFetch(MyRemoteDBClass myRemoteDBClassInstance){
myRemoteDBClassInstance.asyncDataFetch(myClassBObject_as_listener)
}`
The problem is that the calls of ClassA and ClassB are pretty close in timeline and I don't know if I get to call the asyncFetch before or after the init of myRemoteDBClassInstance was already completed.
How can I promise that I get to call myRemoteDBClassInstance.asyncDataFetch method in MyClassB after the init was completed?

Make your some_listener take a CompletableFuture, and resolve it once the asyncAuthenticate is complete. It would end up looking something like this:
CompletableFuture<Void> future = new CompletableFuture<>();
Listener some_listener = new Listener() {
#override onAuthComplete() { future.complete(null); }
//...
};
// Guts of your MyClassA.init
MyRemoteDBClass myRemoteDBClassInstance = new MyRemoteDBClass();
myRemoteDBClassInstance.asyncAuthenticate(some_listener);
// ...
// Guts of your MyClassB.asyncDataFetch
future.get(); // Wait for auth to complete
myRemoteDBClassInstance.asyncDataFetch(other_listener);
I like to use a future, since it allows us to return something more useful than a Void later, or to perform chaining of async calls nicely later.

I would initialize a state in MyClassA, to keep a record whether it is initialized. Then check this state in MyClassB.
Class MyClassA.init()
{
MyRemoteDBClass myRemoteDBClassInstance = new MyRemoteDBClass();
myRemoteDBClassInstance.asyncAuthenticate(some_listener);
static boolean initialized = true;//only sample code
}
static boolean MyClassA.isInitialized() {return initialized ;}
// Then somewhere in the app:
Class MyClassB.asyncDataFetch(MyRemoteDBClass myRemoteDBClassInstance){
if (MyClassA.isInitialized()) { //only sample code
myRemoteDBClassInstance.asyncDataFetch(myClassBObject_as_listener)
}
}

Related

Is it possible to initialize some of the fields in a mock object

I have a code that I cannot correctly cover with tests.
I am using the Mockito library.
And I had difficulty at the moment of starting the test.
Below is the test code:
#Test
public void testLoadCar() {
when(remoteService.loadData()).thenReturn(new DataResult<DataCar>("", "", new DataCar()));
when(dataResult.hasError()).thenReturn(true);
when(dataResult.response.hasHeaders()).thenReturn(true);
requestNetwork = new RequestNetwork(remoteService);
Response<DataCar> response = requestNetwork.load(request);
}
These are objects in the test class: remoteService, dataResult, request.
I am concerned about the moment where I am trying to implement the when method:
when(dataResult.response.hasHeaders()).thenReturn(true);
I would like to know if such a recording will work.
If it doesn't work, then how can we handle this moment:
protected Response createResponse(DataResult<T> dataResult) {
if (dataResult.hasError() || !dataResult.response.hasHeaders()) {
return dataResult.getErrorMessage());
} else {
return Response.data(dataResult.value);
}
}
This is a method on the system under test (SUT) that has a createResponse() method. This method contains a call to the mock method of the DataResult object.
To implement dataResult.hasError () I got it:
when (dataResult.hasError ()). thenReturn (true);
Then with! DataResult.response.hasHeaders () I have a problem. Since I don't understand how to substitute the value I need.
Not all objects that your object under test interacts with need to be mocks.
Remember that you can use POJOs as well.
DataResult looks like a perfect candidate for a POJO.
You gain nothing by using a mock objet if you can create a POJO with desired state and behaviour.
Looking at the posted code, it looks like it is easy to create:
new DataResult<DataCar>("", "", new DataCar())
On top of that:
Your code looks suspicious to me.
when stubbing remoteService.loadData() you create a new instance of DataResult
subsequently, you stub some calls on dataResult, which is not an object returned from remoteService.loadData()
And to answer original post:
You can set fields on mocks (directly if access modifiers allow it, or via reflection otherwise). Note that this is highly not-idiomatic and surprising use of mocks.
class A {
B b;
}
class B {
boolean hasHeaders() {
return true;
}
}
#ExtendWith(MockitoExtension.class)
public class AAATest {
#Mock
A aMock;
#Mock
B bMock;
#BeforeEach
void setupMocks() {
aMock.b = bMock;
}
#Test
void testFieldInMockIsInitialized() {
Assertions.assertEquals(bMock, aMock.b);
}
}

Call kotlin completion in java

I have a kotlin web request method that takes a function as a parameter.
Due to how one of my classes is set up, I need to keep it as a java class but I need to call the web request method from the java class.
I have a class called Lock that I am fetching from my database using Fuel
My kotlin method is as follows
fun fetchLocks(completion: (Array<Lock>) -> Unit) {
// asynchronous api calls that aren't relevant.
completion(locks)
}
I know that this method works and am able to call it from a kotlin file
FuelHelper().fetchLocks { locks ->
Do stuff with my locks
}
The issue I am having is getting the proper syntax in order to call this method in java.
new FuelHelper().fetchLocks();
The parameter java expects is (Function1<?super Lock[], Unit>)
I have tried for a while now and am unable to get past this. Any help would be appreciated.
Assuming that you are using java 8 syntax.
new FuelHelper().fetchLocks(locks -> {
...
});
Or without lambda
new FuelHelper().fetchLocks(new Function1<Lock[], Unit>() {
#Override
public Unit invoke(Lock[] locks) {
return null;
}
});
It's exactly what it says - You have to pass an object implementing interface Function1 (source from generated file Functions.kt):
/** A function that takes 1 argument. */
public interface Function1<in P1, out R> : Function<R> {
/** Invokes the function with the specified argument. */
public operator fun invoke(p1: P1): R
}
In your case you create an anonymous class the same way you do for all small listeners like onClicks etc.:
new FuelHelper().fetchLocks(new Function1<Lock[], Unit>() {
#Override
public Unit invoke(Lock[] locks) {
// handle locks
return null;
}
});

Matching mutable object without ArgumentCaptor

I have to test a method which uses a mutable object
private final List<LogMessage> buffer;
...
flushBuffer() {
sender.send(buffer);
buffer.clear();
}
I need to test that it sends buffers with exact size.
ArgumentCaptor is not applicable because the captured collection is clear by the time of assertion.
Is there a kind of matcher which can reuse Hamcrest's hasSize() and does check right in time of method call?
I would prefer something like this hypothetical collectionWhich matcher:
bufferedSender.flushBuffer();
verify(sender).send(collectionWhich(hasSize(5)));
A lightweight alternative to David's idea: Use an Answer to make a copy at the time of the call. Untested code, but this should be pretty close:
final List<LogMessage> capturedList = new ArrayList<>();
// This uses a lambda, but you could also do it with an anonymous inner class:
// new Answer<Void>() {
// #Override public Void answer(InvocationOnMock invocation) { /* ... */ }
// }
when(sender.send(any())).thenAnswer(invocation -> {
List<LogMessage> argument = (List<LogMessage>) invocation.getArguments()[0];
capturedList.addAll(argument);
});
bufferedSender.flushBuffer();
assertThat(capturedList).hasSize(5);
The Jeff Bowman answer is fine but I think that we can improve it by inlining the assertion in the Answer object itself. It avoids creating unnecessary copy objects and additional local variable(s).
Besides in cases of we need to copy the state of custom objects (by performing a deep copy of it), this way is much simpler. Indeed, it doesn't require any custom code or library to perform the copies as the assertion is done on the fly.
In Java 8, it would give :
import static org.mockito.Mockito.*;
when(sender.send(any())).thenAnswer(invocation -> {
List<LogMessage> listAtMockTime = invocation.getArguments()[0];
Assert.assertEquals(5, listAtMockTime.getSize());
});
bufferedSender.flushBuffer();
Note that InvocationOnMock.getArgument(int index) returns an unbounded wildcard (?). So no cast is required from the caller as the returned type is defined by the target : here the declared variable for which one we assign the result.
You would have the same issue than with ArgumenCaptor as the verify() method checks the invocation with the state of the object after the execution. No capture is performed to keep only the state at the invocation time.
So with a mutable object I think that a better way would be to not use Mockito and instead create a stub of the Sender class where you capture the actual size of the collection as send() is invoked.
Here is a sample stub class (minimal example that you could of course enrich/adapt) :
class SenderStub extends Sender {
private int bufferSize;
private boolean isSendInvoked;
public int getBufferSize() {
return bufferSize;
}
public boolean isSendInvoked(){
return isSendInvoked;
}
#Override
public void send(List<LogMessage> buffer ) {
this.isSendInvoked = true;
this.bufferSize = buffer.size();
}
}
Now you have a way to check whether the Sender was invoked and the size (or even more) of that.
And so put aside Mockito to create this mock and verify its behavior :
SenderStub sender = new SenderStub();
MyClassToTest myClass = new MyClassToTest(sender);
// action
myClass.flushBuffer();
// assertion
Assert.assertTrue(sender.isInvoked());
Assert.assertEquals(5, sender.getBufferSize());

Android Single observer with multiple subscribers in separate classes

ok, so i'm trying to implement rxJava2 with retrofit2. The goal is to make a call only once and broadcast the results to different classes. For exmaple: I have a list of geofences in my backend. I need that list in my MapFragment to dispaly them on the map, but I also need that data to set the pendingIntent service for the actual trigger.
I tried following this awnser, but I get all sorts of errors:
Single Observable with Multiple Subscribers
The current situation is as follow:
GeofenceRetrofitEndpoint:
public interface GeofenceEndpoint {
#GET("geofences")
Observable<List<Point>> getGeofenceAreas();
}
GeofenceDAO:
public class GeofenceDao {
#Inject
Retrofit retrofit;
private final GeofenceEndpoint geofenceEndpoint;
public GeofenceDao(){
InjectHelper.getRootComponent().inject(this);
geofenceEndpoint = retrofit.create(GeofenceEndpoint.class);
}
public Observable<List<Point>> loadGeofences() {
return geofenceEndpoint.getGeofenceAreas().subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.share();
}
}
MapFragment / any other class where I need the results
private void getGeofences() {
new GeofenceDao().loadGeofences().subscribe(this::handleGeoResponse, this::handleGeoError);
}
private void handleGeoResponse(List<Point> points) {
// handle response
}
private void handleGeoError(Throwable error) {
// handle error
}
What am I doing wrong, because when I call new GeofenceDao().loadGeofences().subscribe(this::handleGeoResponse, this::handleGeoError); it's doing a separate call each time. Thx
new GeofenceDao().loadGeofences() returns two different instances of the Observable. share() only applies to the instance, not the the method. If you want to actually share the observable, you'd have to subscribe to the same instance. You could share the it with a (static) member loadGeofences.
private void getGeofences() {
if (loadGeofences == null) {
loadGeofences = new GeofenceDao().loadGeofences();
}
loadGeofences.subscribe(this::handleGeoResponse, this::handleGeoError);
}
But be careful not to leak the Obserable.
Maybe it's not answering your question directly, however I'd like to suggest you a little different approach:
Create a BehaviourSubject in your GeofenceDao and subscribe your retrofit request to this subject. This subject will act as a bridge between your clients and api, by doing this you will achieve:
Response cache - handy for screen rotations
Replaying response for every interested observer
Subscription between clients and subject doesn't rely on subscription between subject and API so you can break one without breaking another

what's a good pattern for registering a Class to execute a specific task later on?

I'm writing a test suite, and I'm thinking about how to mock certain request/response flows. For example, I want to test a method that makes multiple RESTful calls:
getCounts() {
...
Promise<Integer> count1 = getCount1();
Promise<Integer> count2 = getCount2();
// returns a DataModel containing all counts when the Promises redeem
}
getCount1() {
...
Request<Foo> request = new Request<Foo>();
sendRequest(request);
...
}
getCount2() {
...
Request<Bar> request = new Request<Bar>();
sendRequest(request);
...
}
sendRequest(Request<T> request) {...}
However, each getCount() method creates a different Request<T> object, where <T> describes the type of request being made in regards to the count being retrieved. This means I can't simply "mock" the sendRequest() method since it is being called with a different type each time.
I was thinking about an approach where I register a "handler"... when sendRequest() is called, it determines which handler to call, and the handler would know the appropriate type of mock data to return. The registration would be something like storing the handler class type or an instance of the handler class along with the mock data it needs, and when sendRequest() is called, it would look for and invoke the correct handler.
However, I'm not sure if this a good pattern, and I'm wondering if there is a better way of approaching this problem. What is a good pattern for registering a Class or a particular method to execute a specific task later on?
Hard to answer without more context, but the general approach is to use Inversion Of Control (IOC). For example, put the getCountXXX methods into a class of their own, which may be a good idea for better reuse, readability, encapsulation, testability, etc:
public class CountFetcher {
getCount1() { ... }
getCount2() { ... }
}
The original code now gets an instance of CountFetcher using whatever "injection" mechanism is available to you. Simplest is just a constructor:
public class Counter {
private final CountFetcher fetcher;
public Counter(CountFetcher fetcher) {
this.fetcher = fetcher;
}
public getCounts() {
Promise<Integer> count1 = fetcher.getCount1();
Promise<Integer> count2 = fetcher.getCount2();
...
}
}
In your production code, you instantiate Counter with a real CountFetcher. In test code, you inject a mock version of CountFetcher which can have each individual getCountXXX method return whatever you want:
public class MockCountFetcher extends CountFetcher {
#Override
getCount1() { return mockCount1; }
}
public class TestCounter {
#Test
public void smokeTest() {
CountFetcher mockFetcher = new MockCountFetcher();
Counter counter = new Counter(mockFetcher);
assertEquals(someExpectedValue, counter.getCounts());
}
}

Categories