I´m starting to implement the MVP pattern on an Android project and I have some doubts about where I should validate the fields before doing any action.
For example, If I have to send a form with three fields (name, email, text).
Should I validate the fields in the activity or I should send them to the Presenter for being validated?
I'm not 100% sure yet if the comunication with the presenter has to be only with the right data already validated or not.
It really depends, my recommendation is that (And what I normally do):
If the field can be validated without access to database or complex operations, I'd do it in the activity. Examples of such fields would be: Password (Passwords need to contain at least 7 characters), Age (Age must be numeric)
If the field needs to be validated by accessing the database (or by web service) or the operation requires complex logic and resource, do it in the presenter. Examples of such fields would be: Username (To check if it is a duplicated username by accessing the database)
Think of it as a front-end and back-end of a website, although not completely same, it does help you to clarify confusing concepts.
View should never decide to do things by itself, presenter keeps waiting by events notified by view and presenter decides what to do then, view only keeps waiting orders from presenter.
So, no, validation is a presenter task, even if it is a very simple task such as validating a field.
You can do like this in activity:
private Presenter mPrensenter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v) {
mPrensenter.load(name,email,text);
}
});
}
#Override
public void onRightDataValidated(){
}
then there is two interface MainView and Prensenter:
public interface MainView{
void onRightDataValidated();
}
public interface Presenter{
void load(String name,String email,String text);
}
int the impl of the Presenter,when the data need to be invalidate in load method,u can use MainView.onRightDataValidated to callback , u can find more in my github MVP Demo
Part of the point of MVP is to make testing easier. If you approach questions like these asking, "What if I never tested the view," then that gives the right perspective on what logic should or should not go there. The presenter should lend itself to fast JUnit testing and relieve the developer from needing to write Android instrumentation tests.
Bottom line, you're going to want to test your validation logic to be sure it is sound and if you put that in the Presenter, it makes life easier.
Well I believe you should do the validation in activity. And Simply presenter will call the validation method to check if the validation passes then it will complete the action otherwise show the error.!
In one of my client's project, There is detail page and on click of submit button it should check if detailed page filled then it will save the order with the detail otherwise show the error.
And this is how i have implemented--
Here you can see the isDetailFilledOut() is a validation method and it will return true if validation passes otherwise false.
If it returns true it checks if internet also available then it saves the order by calling model's saveOrder method otherwise shows the fill out detail warning.
Related
Jake Wharton delivered a fascinating talk where he proposes some smart ways to improve our UI tests by abstracting the detail of how we perform UI out of the tests: https://news.realm.io/news/kau-jake-wharton-testing-robots/
An example he gives is a test that looks as follows, where the PaymentRobot object contains the detail of how the payment amount & recipient are entered into the UI. Putting that one place makes a lot of sense so when the UI inevitably changes (e.g. renaming a field ID, or switching from a TextEdit to a TextInputLayout), it only needs updating in one place not a whole series of tests. It also makes the tests much more terse and readable. He proposes using Kotlin to make them even terser. I do not use Kotlin but still want to benefit from this approach.
#Test public void singleFundingSourceSuccess {
PaymentRobot payment = new PaymentRobot();
ResultRobot result = payment
.amount(42_00)
.recipient("foo#bar.com")
.send();
result.isSuccess();
}
He provides an outline of how the Robot class may be structured, with an explicit isSuccess() response, returning another Robot which is either the next screen, or the state of the current one:
class PaymentRobot {
PaymentRobot amount(long amount) { ... }
PaymentRobot recipient(String recipient) { .. }
ResultRobot send() { ... }
}
class ResultRobot {
ResultRobot isSuccess() { ... }
}
My questions are:
How does the Robot interface with the Activity/Fragment, and specifically where is it instantiated? I would expect that happens in the test by the runner, but his examples seem to suggest otherwise. The approach looks like it could be very useful, but I do not see how to implement it in practice, either for a single Activity/Fragment, or for a sequence of them.
How can this approach be extended so that the isSuccess() method can handle various scenarios. e.g. if we're testing a Login screen, how can isSuccess() handle various expected results like: authentication success, API network failure, and auth failed (e.g. 403 server response)? Ideally the API would be mocked behind Retrofit, and each result tested with an end to end UI test.
I've not been able to find any examples of implementation beyond Jake's overview talk.
I had totally misunderstood how Espresso works, which led to even more confusion in my mind about how to apply it to the page object pattern. I now see that Espresso does not require any kind of reference to the Activity under test, and just operates within the context of the runner rule. For anyone else struggling, here is a fleshed-out example of applying the robot/page object pattern to a test of the validation on a login screen with a username and password field where we are testing that an error message is shown when either field is empty:
LoginRobot.java (to abstract automation of the login activity)
public class LoginRobot {
public LoginRobot() {
onView(withId(R.id.username)).check(matches(isDisplayed()));
}
public void enterUsername(String username) {
onView(withId(R.id.username)).perform(replaceText(username));
}
public void enterPassword(String password) {
onView(withId(R.id.password)).perform(replaceText(password));
}
public void clickLogin() {
onView(withId(R.id.login_button)).perform(click());
}
}
(Note that the constructor is testing to make sure the current screen is the screen we expect)
LoginValidationTests.java:
#LargeTest
#RunWith(AndroidJUnit4.class)
public class LoginValidationTests {
#Rule
public ActivityTestRule<LoginActivity> mActivityTestRule = new ActivityTestRule<>(LoginActivity.class);
#Test
public void loginPasswordValidationTest() {
LoginRobot loginPage = new LoginRobot();
loginPage.enterPassword("");
loginPage.enterUsername("123");
loginPage.clickLogin();
onView(withText(R.string.login_bad_password))
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)));
}
#Test
public void loginUsernameValidationTest() {
LoginRobot loginPage = new LoginRobot();
loginPage.enterUsername("");
loginPage.enterPassword("123");
loginPage.clickLogin();
onView(withText(R.string.login_bad_username)).check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)));
}
}
Abstracting the mechanisms to automate the UI like this avoids a mass of duplication across tests, and also means changes are less likely to need to be reflected across many tests. e.g. if a layout ID changes, it only needs updating in the robot class, not every test that refers to that field. The tests are also significantly shorter and more readable.
The robot methods, e.g. the login button method, can return the next robot in the chain (ie that operating on the activity after the login screen). e.g. LoginRobot.clickLogin() returns a HomeRobot (for the app's main home screen).
I've put the assertions in the tests, but if assertions are reused in many tests it might make sense to abstract some into the robot.
In some cases it might make sense to use a view model object to hold a set of fake data that is reused across tests. e.g. if testing a registration screen with many fields that is operated on by many tests it might make sense to build a factory to create a RegistrationViewModel that contains the first name, last name, email address etc, and refer to that in tests rather than duplicating that code.
How does the Robot interface with the Activity/Fragment, and
specifically where is it instantiated? I would expect that happens in
the test by the runner, but his examples seem to suggest otherwise.
The approach looks like it could be very useful, but I do not see how
to implement it in practice, either for a single Activity/Fragment, or
for a sequence of them.
The Robot is supposed to be a utility class used for the purpose of the test. It's not supposed to be a production code included as a part of your Fragment/Activity or whatever you wanna use. Jake's analogy is pretty much perfect. The Robot acts like a person interacting with the screen of the app. So the exposed api of a Robot should be screen specific, regardless of what your implementation is underneath. It can be across multiple activities, fragments, dialogs, etc. or it can reflect an interaction with just a single component. It really depends on your application and test cases you have.
How can this approach be extended so that the isSuccess() method can
handle various scenarios. e.g. if we're testing a Login screen, how
can isSuccess() handle various expected results like: authentication
success, API network failure, and auth failed (e.g. 403 server
response)? Ideally the API would be mocked behind Retrofit, and each
result tested with an end to end UI test.
The API of your Robot really should specify the what in your tests. Not the how. So from the perspective of using a Robot it wouldn't care if you got the API network failure or the auth failure. This is how. "How did you end up with a failure". A human QA tester (=== Robot) wouldn't look at http stream to notice the difference between api failure or http timeout. He/she would only see that your screen said Failure. The Robot would only care if that was a Success or Failure.
The other thing you might want to test here is whether your app showed a message notifying user of a connection error (regardless of the exact cause).
class ResultRobot {
ResultRobot isSuccess() { ... }
ResultRobot isFailure() { ... }
ResultRobot signalsConnectionError() { ... }
}
result.isFailure().signalsConnectionError();
I am using RxJava on an Android project and want to make sure I'm implementing something correctly.
I am using an Observable to login to a server. After the login occurs I may want to save the username on the client side so I'm using the doOnNext() operator to do this. Here's an example of what this looks like:
Observable<Response<Void>> doLogin(Observable<Response<Void>> retainedObservable, Subscriber subscriber, String username, String password, boolean saveUsername) {
if (retainedObservable == null) {
retainedObservable = networkLayer.loginWithcredentials(username, password)
.doOnNext(new Action1<Response<Void>>() {
#Override
public void call(Response<Void> voidResponse) {
if (saveUsername) {
databaseLayer.saveUsername(username).subscribe();
} else {
databaseLayer.saveUsername(null).subscribe();
}
}
})
.cache();
}
mSubscription = retainedObservable.subscribeOn().observeOn().subscribe(subscriber);
return retainedObservable;
}
If the device goes through a configuration change before the login finishes I want to be able to resubscribe to the observable that was running so that I don't have to ask the user to reenter their credentials of press the login button again.
To accomplish this I initially call doLogin(...) and temporarily save the returned observable in a data holder class. If the device goes through a configuration change I can grab the already created observable from the data holder class and resubscribe to it. This works great, my only hang up is that I need to also temporarily save off the username, password and saveUsername flag. This is easy enough to do, however I'm wondering if there's a way I can leverage RxJava to hold these values in the Observable and still have access to them when I need them in doOnNext(...). If I don't do this and just resubscribe to the Observable then when doOnNext(...) runs I won't have values for the saveUsername flag or the username which is obviously bad.
It would be really nice to only have to retain the Observable and somehow have it retain the username, password and saveUsername flag. Is there a way to accomplish this in RxJava or is the way I'm currently doing it the way it needs to be done if I want those variables to be retained during a configuration change?
Essentially, yes. RxJava uses a functional, stateless API, so you're not really able (or supposed) to attach additional data to an observable aside from the values it returns.
As with functional languages, there are generally two ways you can go about this:
You can either capture additional values in a closure, similar to how
you are doing it now. But obviously those values will only be
accessible within the scope of said closure, so you can't return an
Observable from a method and still access variables that were used to
create it later.
If you do need to access that data at a later point, the usual approach is to create some kind of result object that contains all your data. For example a "LoginResult" class, that contains your response as well as the original login data.
Let me to start explain my problem. There is repository with some explanations, but there are no methods how to get collection or json file from Meteor server(only insert). Also author did not explain properly methods onDataChanged, onDataAdded etc.
public class Login extends Activity implements MeteorCallback{
public static Meteor mMeteor;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
mMeteor = new Meteor(this, "some_socket_it_doesn't_matter");
mMeteor.setCallback(this);
}
}
public class ListOfElements extends ListFragment implements MeteorCallback{
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
String subscriptionId = Login.mMeteor.subscribe("notifications");
Log.d("Log", subscriptionId);
}
}
I didn't understand how i have to use subscription or how to get collection from server. Why there are only insert methods in github repository and no get? I really have no idea how make the code to get collection, use subscribe and so on. There are no any understandable explanations in the network. Please, can you help me with this by explaining how to realize getting, subscribing in this code.
There are two special things about Meteor: It works asynchronously and it has been designed specifically for real-time applications. Thus it has a few different concepts for retrieving data and for some other tasks.
In a synchronous application, you would just call insert(...) and immediately get the method's return value, e.g. a boolean value for success/error or a numeric value for the number of rows that have been inserted.
You would call get(...) and immediately receive a collection of rows as the method's return value.
But in Meteor, everything is asynchronous. This means that you get the results not immediately, but a few (milli)seconds later, in a callback method.
When you call insert(...), this is not so important, as you have noticed. You just call this method and often forget about the result, i.e. you don't wait and check for the result because insertions are usually successful. But this method is still asynchronous and you could (and sometimes should) listen for the result which will arrive a few (milli)seconds later, again.
When you want to call get(...), this would be possible in theory, with the important point again being that it's asynchronous. So you would say "get me all chat messages from the last 5 minutes". There would be no result or return value, as usual, but the result would arrive a short time later, asynchronously, in a callback method that you define. This is what onDataAdded(...), onDataChanged(...) and onDataRemoved(...) are for.
Now it's not clear, yet, why you can't call get(...) and wait for data to arrive in those methods.
The answer to that question is Meteor being designed for real-time applications. This is why you can't say "get me all chat messages from the last 5 minutes". Instead, you have to say "I want to subscribe to all chat messages from the last 5 minutes and always be updated about changes".
So, in Meteor, you subscribe to data sets instead of requesting them via get(...).
All in all, this means the following:
If you want to get some messages, you subscribe to your data set that holds those messages.
When the initial rows are sent (!) and whenever new rows are added to the collection, you receive those in your onDataAdded(...) callback. When rows are modified, you receive those changes in your onDataChanged(...) callback. And, finally, when rows are deleted, you are informed about those deletions in your onDataRemoved(...) callback.
When you don't want to get updates for your data set anymore, you unsubscribe from that set. This is optional.
With the Android-DDP library in your Android application, it translates to the following:
final String subscriptionId = mMeteor.subscribe("chats");
public void onDataAdded(String collection, String docID, String json) { ... }
mMeteor.unsubscribe(subscriptionId);
As you can see, what you have to learn is really Meteor and not the library Android-DDP. Meteor has some new concepts that one has to understand. But when you know how Meteor works, translating those things to Android-DDP is really simple and only a matter of looking up the method names.
There seems to be no end to the number of posts discussing how to unit test completely unrealistic things.
An abundance of tutorials, videos etc outline what unit tests are and how you do them. There do not however seem to be many (if any) resources which outline how to test something real.
After all.. in reality the 'units' that we are testing are generally significantly more complex than a method taking inputs and giving an output.
I am working with Android at the moment and was investigating how to unit test my application.
My application is essentially made up of views and server requests. You click button x and it changes the view displayed. You click button y and it loads data from the server and populates a list.
Below is some source code. I have essentially pieced together an example setup which demonstrates the things that are confusing (to me). The things that I find conceptually difficult to unit test.
public class ChainActivity extends FragmentActivity {
private PRFragmentTabHost mTabHost;
public GetChainResponse.Data responseData;
Integer chainId; //ref to chain we are getting - passed in
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Get the chain id we are getting
Bundle extras = getIntent().getExtras();
chainId = extras.getInt("chainId");
setContentView(R.layout.activity_base);
//Set up the tabs
mTabHost = (PRFragmentTabHost) findViewById(android.R.id.tabhost);
mTabHost.setup(this, getSupportFragmentManager(), android.R.id.tabcontent);
mTabHost.addTab(mTabHost.newTabSpec("Details").setIndicator("Details", null), ChainDetailsFragment.class, null);
mTabHost.addTab(mTabHost.newTabSpec("Pictures").setIndicator("Pictures", null), PicturesFragment.class, null);
mTabHost.addTab(mTabHost.newTabSpec("Cats").setIndicator("Cats", null), CatsFragment.class, null);
}
#Override
public void onStart() {
super.onStart();
//Initiate the data load
loadChainData();
}
//Method loads the chain data
public void loadChainData(){
PRAPIInterface apiService = ApiService.getInstance();
Integer limit = 4;
apiService.getChain(chainId, limit, new Callback<GetChainResponse>() {
#Override
public void success(GetChainResponse pr, Response response) {
lastData = System.nanoTime();
//Save the response data
responseData = pr.data;
//Get the current tab and pass the loaded data to it
String currentTabTag = mTabHost.getCurrentTabTag();
DataLoadedInterface currentTab = (DataLoadedInterface) getSupportFragmentManager().findFragmentByTag(currentTabTag);
currentTab.dataLoaded(responseData, false);
}
#Override
public void failure(RetrofitError retrofitError) {
// Log error here since request failed
Log.w("Failed", "Failed" + retrofitError.getUrl());
Log.w("Failed", "Failed" + retrofitError.getBody());
}
});
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
Fragment fragment = getSupportFragmentManager().findFragmentByTag(mTabHost.getCurrentTabTag());
if (fragment != null) {
fragment.onActivityResult(requestCode, resultCode, data);
}
}
}
So.. I am aware of Roboeletric, Robotium etc and other libraries that are available for testing on Android. I am however looking for conceptual advice.
Android provides ActivityUnitTestCase
I can subclass this and setup a test for my activity.
Part 1
In principle I could test my onCreate by verifying that mTabHost is not null BUT I don't want to make it publicly available, nor do I want to have a getter to its value.
I figured that I could test the existence of my fragments but i can in fact not. Because the activity runs in 'isolation' it seemingly does not actually create the fragments for the tabs.
Part 2
Next is onStart. This calls another method. It has no return value. I cant test a response.
It is however important that i test that onStart we load our initial data..
Within loadChainData I could set a Boolean indicating that I am loading data and verify this but a coworker could just set this Boolean to true by default and my test would pass.
Furthermore I don't want to test loadChainData 'again'.. I will be testing this method anyway. One idea that springs to mind is stubbing out loadChainData and verifying that it is called and leaving it at that. This however seems to be difficult to do with Android (anyone..?) and does not really fit with the sentiment that testing should be fun.
Part 3
loadChainData loads some data from the server using retrofit. Because in reality this method executes asynchronously there is again no response from this method. I have found an appropriate way of returning mock data by swapping out the retrofit client but doing this swapping is not apparently simple.
At the moment I use a singleton for my ApiService. I want to essentially replace what is built the first time this singleton is called. There are potential complex solutions for this like using a Dependency injection library (like Dagger) but given what I want to achieve I feel that there should be a much simpler way of doing this.
My initial thoughts are that if the application could be instantiated with say a test flag. The singleton would return the test client. Alternatively it would default to the real client. This in my mind smells a little.. could someone explain what the smell is, and how one could appropriately resolve it?
Even if the above was considered a fair suggestion there seems to be no easy way to actually do it with ActivityUnitTestCase.
Part 4
Finally is onActivityResult.
Again, there is no response.
This time the method in question interacts with other units elsewhere. Units that act differently within the constraints of ActivityUnitTestCase anyway.
I could wrap my manipulation of the support fragment manager, mock my wrapper, return a mocked fragment, verify that its onActivityResult method is called.. but again this seems incredibly tough to do. Furthermore this adds complexity to my code to allow something to be testable. I have no interest in increasing complexity just to test..
So..
Does anyone with real experience unit testing on mobile have any insight on how to appropriately tests a class such as this one. As you can see it is not really a case of 'put 2 in, does 4 come out' :)
A lot of resources mention how testing is underdone. This is why :) Any advice would be greatly appreciated.
T
onCreate
I would test in two ways, one using some form of AndroidTestCase this would allow the testing of extras you send in the Bundle.
( I would add error handling to throw an error if the extra is not present )
( I would change loadChainData() to take chainId as a paramater )
To test your tabs are instantiated correct I would use espresso for an Acceptance test to validate your views are present.
onStart
There is no Dependency Inversion here and so you cannot test the service methods are called. You would want to test getChain is called. What happens when you create that service, could you do it in the constructor?
( I would move away from the Activity here and encapsulate all behaviour from onStart in some other class [perhaps MVC could help] that way you aren't constrained by the lifecycle.
( I would also add another layer of callback's on top of Volley in to the Activity, that way you can test your listeners return the correct success or failure, but you don't have to worry about the tabs [the activity ui]).
If you really wanted to test asynchronisity (which I wouldn't advise) you can use Espresso and that can help you manage the test to still get callbacks see custom resource idoling.
onActivityResult
I believe using Robolectric you could pass it a Mockito mock fragment manager in order to return you a stub fragment and validate the behviour of the the fragment tab host, then you would call onActivityResult yourself: whether testing this actually gives you any benefit is another question.
Overall testing lifecycle methods is like testing anything else, for it to be testable you need to abstract away any ideas of threading, you need to be in control of your dependencies and I find the closer you adhere to SOLID the easier testing is. In the wake of these stumbling blocks, this is why Robolectric, InstrumentationTests and Espresso where created.
In summary sorry, there is no straight forward answer here, you have to ask yourself - do I get any benefit from testing these things, am I testing my code or am I testing the framework, what is the cost benefit of testing this Activity does it actually encumber future changes rather than gain me confidence.
I am from an Android background and am progressing into Windows Phone 8.
I have a Page that uses the camera to decode a QR code and this works fine. In Android I would start this Activity using the Intent StartActivityForResult, which would then give me the decoded value back to the original Activity.
I have searched but could not find an obvious equivalent in Windows Phone 8. My thought at the moment is to navigate to the calling page with a query string containing the decoded value and alter the back stack, but this seems a little messy.
The Question
Is there an equivalent to the process in android, and if so can someone outline the methodology so I may see it in action?
First, there's no such thing in WP8, so you'll need a workaround. Workarounds could be different, and the linked question (and answer) is one of the potential approaches. I personally do this a bit differently. I'll describe my current project's architecture here, though it may not be applicable to your situation, since my app is quite big and has a complex structure. But I'll try to explain how it could be applied to your situation.
Particularly, my current app consists of so called services (just my name, not a standard one). Those have different scope (some are used by 1 page, some are global for the app), different lifetime, and so on. Essentially, every service is a class implementing a well-defined interface, so that other services could use that.
Next, services could depend on each other. I'm using Ninject framework for dependency injection. Essentially, if service A depends on service B, it leads to a code like this:
public class B : IB
{
...
}
public class A
{
IB b;
public A(IB b)
{
this.b = b;
}
}
where IB is an interface, which service B implements.
Then I have view models (yes, I'm using MVVM and you probably should too, if you want to build a reasonably big WP8 app). View models are using services to perform app functions. Some of the services are used by several view models. For example, I have one service that fetches some data from the web, and keep it up to date with periodic polling. That web data is used in several pages of the application, so it should be shared between different view models. It is achieved by dependency injection again, so that all interested view models accept this service instance as a constructor parameter.
public class MainPageViewModel : INotifyPropertChanged
{
private string webData;
public MainPageViewModel(IWebDataService service)
{
webData = service.CurrentWebData;
service.WebDataChanged += (o, e) => webData = service.CurrentWebData;
}
...
}
public class DetailPageViewModel : INotifyPropertChanged
{
private string webData;
public DetailPageViewModel(IWebDataService service)
{
webData = service.CurrentWebData;
service.WebDataChanged += (o, e) => webData = service.CurrentWebData;
}
...
}
public class WebDataService : IWebDataService
{
public string CurrentWebData;
public event EventHandler WebDataUpdated;
...
}
Ninject allows me to have a single instance of IWebDataService instantiated, so that main and details page share the same instance of it. When the web data is updated, an event is fired, so that both view models can update their instances of web data, and push this new data to the views.
So here's how I do it. You could potentially reuse some part of this architecture, like having a singleton instance of some class accessible by different pages. One page puts some new data to that singleton instance, and, when data is updated (event fired or during construction, if garbage collector had enough time to kill existing page and/or view model instance), another page reads the updated data. That's how they share.
If you want me to go deeper into details on some topic, please feel free to ask in comments. Android developers are more than welcomed to the Windows Phone. :)