My android app communicate with backend service through REST API . I want to mock out this API to quickly develop the front end.
I am using android volley as client side networking library.
You can use the dependency injection design pattern for this.
Basically you specify an interface that defines a set of methods corresponding to the queries you have in your REST backend, e.g.:
interface DataSupplier {
// Lookup user by ID
User getUser(int id);
// Get all blog posts posted by a specific user.
List<BlogPost> getUsersBlogPosts(int userId);
}
Now in the class where you need to query the backend, you specify an injector. This can be done in multiple ways (e.g. constructor injection, setter injection - see the wiki article for more details). An injector lets you inject an implementation of the dependency into the class that depends on it. Let us assume you use constructor injection. Your class that uses the backend would look like this:
public class DependentClass {
private final DataSupplier mSupplier;
public DependentClass(DataSupplier dataSupplier) {
mSupplier = dataSupplier;
}
// Now you simply call mSupplier whenever you need to query the mock
// (or - later in development - the real) REST service, e.g.:
public void printUserName() {
System.out.println("User name: " + mSupplier.getUser(42).getName());
}
}
Then you create a mock implementation of DataSupplier:
public class MockRestService implements DataSupplier {
#Override
public User getUser(int id) {
// Return a dummy user that matches the given ID
// with 'Alice' as the username.
return new User(id, "Alice");
}
#Override
public List<BlogPost> getUsersBlogPosts(int userId) {
List<BlogPost> result = new ArrayList<BlogPost>();
result.add(new BlogPost("Some Title", "Some body text"));
result.add(new BlogPost("Another Title", "Another body text"));
result.add(new BlogPost("A Third Title", "A third body text"));
return result;
}
}
and use that to instantiate your dependent class:
DepedentClass restClient = new DepedentClass(new MockRestService());
Now you can use restClient as if it was connected to your actual backend. It will simply return dummy objects that you can use to develop your front end.
When you are done with your front end and ready to implement your backend, you do so by creating another implementation of DataSupplier that sets up a connection to your REST backend and queries it for real objects. Let us say you name this implementation RestService. Now you can simply replace the constructor creating the MockRestService with your RestService constructor like so:
DepedentClass restClient = new DepedentClass(new RestService());
And there you have it: by swapping a single constructor call, you can change your front end code from using dummy objects to using real REST-delivered objects.
You could even have a debug flag and create the restClient according to the state of your application (debug or release):
boolean debug = true;
DependentClass restClient = null;
if (debug) {
restClient = new DepedentClass(new MockRestService());
} else {
restClient = new DepedentClass(new RestService());
}
I've recently created RESTMock. It is a library for Mocking REST API's in android tests. It can be used during development though. You would need to set it up following the README on github and create a basic Android Instrumentation test that would start your app and do nothing. This way the app is started with the Mock Server in background.
Example test:
public class SmokeTest {
#Rule public ActivityTestRule<MainActivity> rule = new ActivityTestRule<MainActivity>(
SplashActivity.class,
true,
false);
#Test
public void smokeTest() throws InterruptedException {
rule.launchActivity(null);
Thread.sleep(10000000);
}
}
Related
I have a JSON file in the assets folder and DataManager(repository) class needs it so assetManager(and context) should have access to the assets.
The problem is that based on Best practice, Android context or android specific code should not be passed into the data layer(ViewModel-Repo-Model) because of writing unit tests or etc easily and also view should not interact with the data layer directly.
I ended up providing the list using and injecting it to the repository.
Is this the right thing to do?
-Thanks
P.S: my Module class which provides the list
#Module
public class UtilModule {
#Provides
#JsonScope
JsonUtil provideJsonUtil(AssetManager assetManager){
return new JsonUtil(assetManager);
}
#Provides
#JsonScope
String provideJson(JsonUtil util){
return util.getJson();
}
#Provides
#JsonScope
Type provideType(){
return new TypeToken<List<Data>>() {}.getType();
}
#Provides
#JsonScope
DataManager provideDataManager (Gson gson, Type type,String json) {
return new DataManager (gson.fromJson(json, type));
}
}
It's not a violation of MVVM for a ViewModel and/or Repository to access the Application context directly, which is all you need to access the AssetsManager. Calling Application.getAssets() is OK because the ViewModel doesn't use any particular Activity's context.
For example, you can use the Google-provided AndroidViewModel subclass instead of the superclass ViewModel. AndroidViewModel takes an Application in its constructor (ViewModelProviders will inject it for you). You could pass your Application to your Repository in its constructor.
Alternately, you could use Dagger dependency injection to inject an Application directly into your Repository. (Injecting the Application context is a bit tricky. See Dagger 2 injecting Android Context and this issue filed on the Danger github repo.) If you want to make it really slick, you could configure a provider for AssetManager and inject it directly into your Repository.
Finally, if you are using Room, and all you want is to pre-populate your Room database with a pre-configured database stored in assets, you can follow instructions here: How to use Room Persistence Library with pre-populated database?
Since you are using MVVM for the first time, we can try to keep things simple.
[ View Component C] ---- (observes) [ ViewModel Component B ] ---- [ Repository ]
According to the Separation of Concerns rule, the ViewModel should expose LiveData. LiveData uses Observers to observe data changes. The purpose of the ViewModel is to separate the data layer from UI. ViewModel should not know about Android framework classes.
In MVVM Architecture, the ViewModel's role is to fetch data from a Repository. You can consider either storing your json file as a local data source using Room, or keeping the Json API as a remote data source. Either way, the general implementation is as follows:
Component A - Entity (implements your getters & setters)
Method 1: Using Room
#Entity(tableName = "file")
public class FileEntry{
#PrimaryKey(autoGenerate = true)
private int id;
private String content; // member variables
public FileEntry(String content){ // constructor
this.id = id;
this.content = content;
}
public int getId(){ // getter methods
return id;
}
public void setId(int id){ // setter methods
this.id = id;
}
public String getContent(){
return content;
}
public void setContent(String content){
this.content = content;
}
}
Method 2: Using Remote Data Source
public class FileEntry implements Serializable{
public String getContent(){
return content;
}
private String content;
}
Component B - ViewModel (Presentation Layer)
Method 1: Using Room
As you asked about how android context can be passed, you can do so by extending AndroidViewModel like below to include an application reference. This is if your database requires an application context, but the general rule is that Activity & Fragments should not be stored in the ViewModel.
Supposing you have "files" as a member variable defined for your list of objects, say in this case, "FileEntry" objects:
public class FileViewModel extends AndroidViewModel{
// Wrap your list of FileEntry objects in LiveData to observe data changes
private LiveData<List<FileEntry>> files;
public FileViewModel(Application application){
super(application);
FilesDatabase db = FilesDatabase.getInstance(this.getApplication());
Method 2: Using Remote Data Source
public class FileViewModel extends ViewModel{
public FileViewModel(){}
public LiveData<List<FileEntry>> getFileEntries(String content){
Repository repository = new Repository();
return repository.getFileEntries(content);
}
}
In this case, getFileEntries method contains MutableLiveData:
final MutableLiveData<List<FileEntry>> mutableLiveData = new MutableLiveData<>();
If you are implementing using Retrofit client, you can do something similar to below code using asynchronous callbacks. The code was taken from Retrofit 2 Guide at Future Studio with some modifications for this discussion example.
// asynchronous
call.enqueue(new Callback<ApiData>() {
#Override
public void onResponse(Call<ApiData> call, Response<ApiData> response) {
if (response.isSuccessful()) {
mutableLiveData.setValue(response.body().getContent());
} else {
int statusCode = response.code();
// handle request errors yourself
ResponseBody errorBody = response.errorBody();
}
}
#Override
public void onFailure(Call<ApiData> call, Throwable t) {
// handle execution failures like no internet connectivity
}
return mutableLiveData;
Component C - View (UI Controller)
Whether you are using Method 1 or 2, you can do:
FileViewModel fileViewModel = ViewModelProviders.of(this).get(FileViewModel.class);
fileViewModel.getFileEntries(content).observe(this, fileObserver);
Hope this is helpful.
Impacts on Performance
In my opinion, deciding whether to use which method may hinge on how many data calls you are implementing. If multiple, Retrofit may be a better idea to simplify the API calls. If you implement it using Retrofit client, you may have something similar to below code taken as provided from this reference article on Android Guide to app architecture:
public LiveData<User> getUser(int userId) {
LiveData<User> cached = userCache.get(userId);
if (cached != null) {
return cached;
}
final MutableLiveData<User> data = new MutableLiveData<>();
userCache.put(userId, data);
webservice.getUser(userId).enqueue(new Callback<User>() {
#Override
public void onResponse(Call<User> call, Response<User> response) {
data.setValue(response.body());
}
});
return data;
}
The above implementation may have threading performance benefits, as Retrofit allows you to make asynchronous network calls using enqueue & return the onResponse method on a background thread. By using method 2, you can leverage Retrofit's callback pattern for network calls on concurrent background threads, without interfering with the main UI thread.
Another benefit of the implementation above is that if you are making multiple api data calls, you can cleanly get the response through an interface webservice above, for your LiveData. This allows us to mediate responses between different data sources. Then, calling data.setValue sets the MutableLiveData value & then dispatches it to active observers on the main thread, as per Android documentation.
If you are already familiar with SQL & only implementing 1 database, opting for the Room Persistence Library may be a good option. It also uses the ViewModel, which brings performance benefits since chances of memory leaks are reduced, as ViewModel maintains fewer strong references between your UI & data classes.
One point of concern may be, is your db repository (example, FilesDatabase implemented as a singleton, to provide a single global point of access, using a public static method to create the class instance so that only 1 same instance of the db is opened at any one time? If yes, the singleton might be scoped to the application scope, & if the user is still running the app, the ViewModel might be leaked. Thus make sure your ViewModel is using LiveData to reference to Views. Also, it might be helpful to use lazy initialization so that a new instance of the FilesDatabase singleton class is created using getInstance method if there are no previous instances created yet:
private static FilesDatabase dbInstance;
// Synchronized may be an expensive operation but ensures only 1 thread runs at a time
public static synchronized FilesDatabase getInstance(Context context) {
if (dbInstance == null) {
// Creates the Room persistent database
dbInstance = Room.databaseBuilder(context.getApplicationContext(), FilesDatabase.class, FilesDatabase.DATABASE_NAME)
Another thing is, no matter your choice of Activity or Fragment for your UI, you will be using ViewModelProviders.of to retain your ViewModel while a scope of your Activity or Fragment is alive. If you are implementing different Activities/Fragments, you will have different instances of ViewModel in your application.
If for example, you are implementing your database using Room & you want to allow your user to update your database while using your application, your application may now need the same instance of the ViewModel across your main activity and the updating activity. Though an anti-pattern, ViewModel provides a simple factory with an empty constructor. You can implement it in Room using public class UpdateFileViewModelFactory extends ViewModelProvider.NewInstanceFactory{:
#Override
public <T extends ViewModel> T create(#NotNull Class<T> modelClass) {
return (T) new UpdateFileViewModel(sDb, sFileId);
Above, T is a type parameter of create. In the factory method above, the class T extends ViewModel. The member variable sDb is for FilesDatabase, and sFileId is for the int id that represents each FileEntry.
This article on Persist Data section by Android may be more useful than my comments if you would like to find out more, on performance costs.
How to verify a void method call in Robolectric test case where as no data coming out the called method.
What to assert in this case? Below given an example of the requirement.
public class SampleClass(){
final String TAG = SampleClass.class.getSimpleName();
public void log(){
Log.d(TAG, "Entry Loggd");
}
}
#Test
public void logEntry_test(){
SampleClass sc = new SampleClass();
sc.log();
// What to assert here to verify this log method
}
First off, good on you for writing tests!!! There are a few ways to go about testing that an internal logger is called. It's equally as important to understand what you're looking to test. Testing that a class is logging a specific message is most likely a fragile test, so be fore-warned that you probably don't need it.
Method #1: Using Robolectric
Robolectic documentation doesn't lend itself to answering basic questions, but its codebase is very well documented with its tests. A basic understanding of its principles and how shadows work can get you a long way. ShadowLog tests lay the ground work to this solution.
#RunWith(RobolectricTestRunner.class)
public class SampleClassTest {
#Test
public void log_writesExpectedMessage() {
new SampleClass().log();
ShadowLog.LogItem lastLog = ShadowLog.getLogs().get(0);
assertThat(lastLog.msg).isEqualTo("some message");
// or
assertThat(lastLog.msg).isNotNull();
}
}
Tests using Robolectric v3.1.2
Add the following to your build.gradle file:
testCompile 'org.robolectric:robolectric:3.1.2'
Method #2: Making use of Abstractions
If your sample class derives from an Android class (Activity, Fragment, Application, etc), then using android.util.Log makes sense, but bear in mind that your test will need to be a Robolectric or AndroidInstrumented test. If your SampleClass is just some POJO, then using a simple logging framework may make your testing efforts easier. For example, using Jake Wharton's Timber, your class and test can be written as follows:
import timber.log.Timber;
public class SampleClass {
void log() {
Timber.d("some message");
}
}
// SampleClassTest.java
public class SampleClassTest {
// setting up a Tree instance that we define below
TestTree testTree = new TestTree();
#Test
public void log_writesExpectedMessage() {
// setting up Timber to us the test classes log writer
Timber.plant(testTree);
// invoke the logging function
new SampleClass().log();
// assert
assertThat(testTree.lastMessage).isEqualTo("some message");
}
private class TestTree extends Timber.Tree {
private String lastMessage;
#Override
protected void log(int priority, String tag, String message, Throwable t) {
lastMessage = message;
}
}
}
Good luck, happy testing!
In my understanding you want to mock static methods. I guess, using static mocks are not the most elegant way to testing. Better to use an abstraction as recommended by abest. Although, it can be done with PowerMock.
In my Android app I have to query some user/session dependent data from a rest webservice. Now I need a way to keep the received webservice results in memory, so that serveral activities/fragments can access them.
I don't want to persist the data (for example a list of the users bank accounts) into a database on the device, because the data expires after a while or when the user logs out.
I also don't want to request the data again and again from webservice, when the user navigates to another activity.
Are there any approved patterns to keep a set of data (some pojo's with more or less properties) in memory during the application is running?
Just for info: I'm experimenting with dagger2, mvp, retrofit2, rxandroid
Regards
Martin
If you already experimenting with Dagger 2, then all you need to do is instantiate a component in Application and use this component in your Activities and Fragments in order to inject a scoped "service".
For example:
Create a class named XyzManager (where Xyz = the actual functionality this manager is responsible for)
Annotate its #Provides method (in Dagger's module) with #Singleton scope
Make sure that the component that injects XyzManager instantiated in Application and add getComponent() method to your custom Appliaction class
In your Activities and Fragments inject XyzManager while using the same component - ((MyApplication)getApplication()).getComponent().inject(this)
If you take the above steps, then all your Activities and Fragments will get a reference to exactly the same instance of XyzManager, and the data you cache in this manager will be accessible everywhere.
The structure you would get is very similar to the structure described in this answer.
Please note that this approach is much better than resolving to static things (e.g. Singleton pattern, or what #KhalidTaha suggested in his answer).
You might want to take a look at my post concerning Dagger 2 scopes if you need a detailed information on that aspect of the framework.
here is a solution:
1- create a DefaultUtil class:
public calss DefaultUtil{
private List<User> listOfUsers;
public static DefaultUtil getInstance(){
if(instance == null)
{
instance = new DefaultUtil();
}
return instance;
}
public List<User> getUserList(){ return listOfUsers; }
public void setUserList(List<User> userList) {
this.listOfUsers = userList ;
}
}
2- when you finish the webservice, call this code:
DefaultUtil.getInstance().setUserList(myWebserviceListOfUsersResult);
and then you can access the list of users from any class by this:
DefaultUtil.getInstance().getUserList();
#Vasiliy
I've studied the linked answer, but I don't get it. I don't use my BankingSession singleton in an activity directly, so calling "getComponent().inject(this).... " won't work. I use the singleton in other service classes (not Android services... just business logic).
// this should be a single instance across the whole app
#Singleton
public class BankingSession {
#Inject
public BankingSession() {
}
}
public class SessionServiceImpl implements SessionService {
private final BankingSession bankingSession;
#Inject
public SessionServiceImpl(BankingSession bankingSession) {
this.bankingSession = bankingSession;
}
}
#Module
public class SessionModule {
#Provides
public SessionService provideSessionService(SessionServiceImpl sessionService) {
return sessionService;
}
}
#Singleton
#Component(modules = {AppModule.class, NetworkModule.class, SessionModule.class})
public interface AppComponent {
Application application();
LoginComponent plus(LoginModule module);
AccountComponent plus(AccountModule module);
BankingSession bankingSession();
}
No matter how I try it, the constructor of BankingSession get's called multiple times
I would like to implement a service(Web service) call in my application.
I blocked here for a while.
Previously I followed some of the below concepts.
like, AsyncTask class, Thread concepts and Handlers.
Recently I heard about the Retrofit.
Based on by experience, retrofit was good with high performance.
But it's not that much of reliable.
Example:
{
"Tag1":"Tag Value",
"TagArray":[ {"key1":"value","key2":"value"},{"key1":"value","key2":"value"},{"key1":"value","key2":"value"} ]
}
POJO:
public class Data{
String key1,key2;
sterres...
getters..
}
If the response have some other tags that are no need and the inside data only we need in our app i,e. "TagArray".
I need the handle only this response.
In such type of case this retrofit was failed.
Is there any other libraries or any other components to implement service calls in android with high performance are existed.
You can add your POJOs' or Beans' fields #Optional. This option comes from GSON that used in Retrofit as default.
EDIT :
public class ExamplePojo implements Serializable {
#SerializedName("TagArray")
public ArrayList<Keys> TagArray;
public ExamplePojo() {
TagArray = new ArrayList<>();
}
public static class Keys{
#SerializedName("key1")
public String key1;
#SerializedName("key2")
public String key2;
}
}
The attributes which you ignore shouldnt be added on POJO class or as mention above, add optional annotation if it can be null.
I have a function that I want to test which runs in an okHttp callback. I'm trying to test it using Robolectrics but the callback is never executed. I presume that is because the test moves on after request without waiting for okHttp to return. So far I've tried:
ShadowLooper.pauseMainLooper();
Robolectric.flushBackgroundScheduler();
ShadowLooper.unPauseMainLooper();
but that didn't work. Any suggestions?
EDIT:
Here's an example of my code:
ApiClient.sendSomeDataToServer(data, callback);
Where ApiClient is a helper class containing okHttp client. sendSomeDataToServer API call looks something like this:
public static void sendSomeDataToServer(MyObject data, Callback callback){
final Request request = new Request.Builder()
.url(API_SOME_URL)
.post(RequestBody.create(JSON, myObject.getAsJson().toString()))
.build();
sHttpClient.newCall(request).enqueue(callback);
}
Where sHttpClient is an initialised OkHttpClient.
I can test the execution of above by forcing Thread.sleep(5000) inside my test code and providing custom callback. The code I'm trying to test is inside the callback. Any suggestions how I can test that? I really don't want to change the main code to fit the test framework - should be the other way round.
Lets assume you have next code. Interface:
#GET("/user/{id}/photo")
void listUsers(#Path("id") int id, Callback<Photo> cb);
Implementation:
public void fetchData() {
RestAdapter restAdapter = new RestAdapter.Builder()
.setServer("baseURL")
.build();
ClientInterface service = restAdapter.create(ClientInterface.class);
Callback<Photo> callback = new Callback<Photo>() {
#Override
public void success(Photo o, Response response) {
}
#Override
public void failure(RetrofitError retrofitError) {
}
};
service.listUsers(435, callback);
}
First of all you need to change service instantiation to service injection (as parameter or field). I will do it as parameter:
public void fetchData(ClientInterface clients) {
}
After this text is quite trivial:
#Test
public void checkThatServiceSuccessIsProcessed() {
ClientInterface mockedClients = mock(ClientInterface.class);
activity.fetchData(mockedClients);
// get callback
ArgumentCaptor<Callback<Photo>> captor = (ArgumentCaptor<Callback<Photo>>)ArgumentCaptor.forClass(Callback.class);
verify(mockedInterface).listUsers(anything(), captor.capture());
Callback<Photo> passedCallback = captor.value();
// run callback
callback.success(...);
// check your conditions
}
The used library for mocking and verifying is Mockito.
There will be one warning with captor instantiation because of generics but it fixable if you will use #Captor annotation instead of creating captor by hands.
The parameter injection is not perfect, especially for case of activities. This was used to simplify example. Consider for proper injection with library or without. I would encourage you to try Dagger for injections
You can use ArgumentCaptor (Mockito's class).
Reference:
http://www.mdswanson.com/blog/2013/12/16/reliable-android-http-testing-with-retrofit-and-mockito.html