I am new for Junit testing framework. Is it possible to test a flow of activities with assertions to check if each is launched using only exisiting classes provided in android API.
It seems we can only test at activity level. But can we automate a flow : like spawning front and back between activities ?
Yes, through the use of Android instrumentation, which provides you with methods that put you into the drivers seat when interacting with activities as the system would through it's instrumentation framework.
Basically, your able to trigger and manage every aspect of an activities life cycle, including introspecting results from activities calling each other. So if you've worked with the ActivityTestCase that's suitable when testing a single activity, you can have a look at the InstrumentationTestCase that provides you with a low-level approach to work with multiple activities at once.
Related
Android Espresso testing app flow
I use Espresso to test a lot of activities and transitions between them. I want to write different test for those activities and link the Activity Intents to the corresponding test cases.
1 . Activity A (testActivityA runs) 2. ActivityA launches ActivityB (testActivity B) should be called
is it possible to do this with espresso or any other test framework?
You should test each activity independently of the others. If you need them to react to incoming intents, you can do that using Espresso Intents.
I am heavily testing my application with unit tests and Espresso tests. My next step is to make sure my application hits all required apis. For that reason I am looking for a way to write a test, which will verify the api calls.
I would really appreciate any suggestions.
What you are describing is called a "unit test". Unit tests are meant to test as many lines of code as possible regardless of UI.
Espresso tests are "instrumentation tests" (or "UI tests") intended to check if the app is responding to UI events correctly. They're not meant to verify the correctness of code, but the correctness of the functionality of the app as used by the user.
You can read about both at the official documentation. You'll find that unit tests are very different than instrumentation tests, and often harder to write because they require more engineering of your code to do correctly. You will likely have to "mock" the various parts of your application to make sure their APIs were called exactly as you expected.
There are 2 main goal when I was writing api tests:
First is component based. The goal was to make sure each class / component makes an api call when certain criteria is met (for example calling an api A when onDestroy() is called)
Second, is to make sure the Apis are called is certain order for the analytics purposes.
The first step I achieved by using unit tests with injected mock objects via Mockito and PowerMockito. PowerMockito was used primarily to mock static methods and to make sure the methods were called at least n times.
For the second step, UI test could be used, since it runs the real application. I have implemented the helper class, which was recording the instances when api requests were made. The script in Espresso was validating the order of api calls by referring the helper class.
I have troubles with my Robolectric unit test.
I can assert without problem that a click started a new activity when the listener uses the method startActivity( Intent )
But it seems Robolectric has trouble when a new activity is started with the method startActivityForResult(Intent, int) : putting some breaks in the code made me figure out that the activity wasn't started ( and just changing for method startActivity( Intent ) made the assert pass).
Is that normal ? It's a pity since the first activity of my app uses startActivityForResult(Intent, int).
Did someone manage to make tests with this way of launching activities ?
Thanks for your help ..
The short Answer to your question is that, due to the way Robolectric converts Android classes to code that executes in the JVM, a lot of their functionality doesn't behave as you'd expect. Many system callbacks won't execute, and you'll have to rely on what Robolectric provides in their Shadow implementation of classes. (See the link provided by #Steven_BDawg).
The long answer: It may be possible to implement this whole flow in one big test, but it's not what the framework is designed for.
Robolectric and Unit Testing in general aren't meant to be used in the way that you describe. The Unit Testing page on wikipedia states that one can view a unit as the smallest testable part of an application. A unit testing suite should contain many lightweight tests, where each test isolates a bit of functionality in your app and ensure it's working properly.
Consider a basic Application that contains two Activities, A and B. Activity A displays some information about a topic, and Activity B allows the user to select which topic to show in A. When the user moves from Activity A to Activity B, B gets called with startActivityForResult() and should return to A with the selected topic.
Now say we want to Unit Test this flow of A getting the result from B and displaying the data. We can break this up into two tests:
Activity Under Test - Activity A. In our test, we'll create a new instance of Activity A. In the Robolectric Test, we create the Intent that we expect B to return to A, and call the shadow method receiveResult() for A, filling out the arguments with a result code of OK and this Intent. After receiveResult(), run your assertions. You now know that Activity A handles the result properly!
Activity Under Test - Activity B. In our test, we'll create a new instance of Activity B, setting it up as if it were started for result from Activity A. In the Robolectric Test, we'll perform all actions needed to select the data, create the intent we'll send back, then run assertions on the intent to ensure it was created correctly.
This is a very simple example. These two steps could probably be broken out into many more tests, as, again, each unit test should only be testing the smallest unit of functionality that your app can be broken into. The example is mainly to help you start thinking in a unit testing kind of way. I've found that as my understand of unit testing deepens, the way I write code has changed. I try to avoid writing methods and classes in such a way that they do too much work and cannot be properly unit tested. As a rule of thumb, code that's easy to unit test performs very specific operations which are readily apparent when reading the code for the first time.
Finally, if you want to take this a step further, mocking frameworks can greatly aid your ability to Unit Test. Mockito is a mocking framework I've had success with in the past. The purpose of a mocking framework is to create stub Objects whose behavior you tightly control. Mockito (or any other Mocking Framework), will allow you to define an object that extends from any type you need and only implement the methods you need. You'll be able to directly control the response to any of these method invocations. This aids Unit Testing because the only real object that you'll need is the Object Under Test; by Mocking all other objects, you'll have a better sense of whether or not the Object Under Test is behaving properly because all other behavior is explicitly defined by you, the tester. (And yes, this does lead to lots of extra code, but such is the life of a good unit tester. However, as previously stated, as you get more comfortable with unit testing, you may find yourself writing methods that require less mocking and are more conducive to writing tests. Some coders will even write their unit tests BEFORE they code, in order to keep their code tight and focused on a single purpose)
Hope this helps!
I did some Google'ing for you. I don't know if this will definitely help you or not, but I think it is a good start!
Roboelectric: Testing startActivityForResult() and onActivityResult()
According to the Robotium doc we can not write test case spans two applications, it says "the test project is locked to the targetPackage. Going outside of that target package is not allowed by the Android platform. Therefore you will need 2 test projects, one for each application."
Currently what I want to do is like monkey tool. I want to randomly fire actions on the screen to exhaustively trigger application's function. During the traversing process, the program flow sometimes will go out of the application and then JUnit or Robotium lose control of the program. I want to know is there any way that I can direct the program flow back to the application? Or is there any way that I can take control of multiple applications at the same time?
Thanks!
One Easy thing to do with write a simple Application which access the Activity Manager and reads every 2 seconds what is active as an external service within your app or another application altogether.
http://developer.android.com/reference/android/app/ActivityManager.html
Basically, check that the ActivityManager.RecentTaskInfo() and check that the Activity Component it was started from is one which you are OK with. Then, so that it does not affect your normal user, .isUserAMonkey() return a boolean of true.
If the Activity is not what you want, write:
else
startService(new Intent(this, TheService.class));
or
else
startActivity(new Intent(this, TheActivity.class));
If you're willing to test only on Android 4.1 and above, you can use the new UI Automator framework, which supports testing across multiple packages.
Some info:
https://plus.google.com/103712615773524578393/posts/dzqtF7BYyG4
how does a good architecture for an android app look like? Should all the "work/business logic" been done in a background service and the Activity communicates just with the service to query/fetch data from somewhere (local/distant)?
Would you implement the "service" that the Activity calls as a real Android-service? Or a POJO-Singleton that does the work (perhaps using background threads). Or instantiate background threads in your activity for time-consuming actions (query a webservice).
How do you abstract your data access the right way? Would you use a ContentProvider to access/abstract your data? How/From where should it be queried? Activity? Service? ..?
I've tried to search for a good app architecture design, but I only found how the Android architecture looks like, not how an Android app should look like.
So what's your opinion about that? What components of an Android application should communicate which each other to ensure best extensibility/encapsulation,...?
There's no one answer to this question. Good OO design isn't Android specific. I'd say that the rule is - if the framework gives you a high level object (such as Service in the case of Android) that fits your use case, use it. If you find yourself making POJO implementations of the same things you get for free with the framework, go with the framework.
As far as separation of concerns, this is standard OO stuff. Don't put anything in your Activity classes that isn't the job of the Activity. Over-stuffing the Activity with methods and properties that the Activity needs but aren't really the job of the Activity is bad - makes the intention of your Activity hard to understand.
I usually separate stuff into sub-packages in my apps.
com.myname.myproject.app - base classes, global application functionality
com.myname.myproject.net - network stuff, network related utils
com.myname.myproject.data - db helpers, providers, etc
com.myname.myproject.model - object model
etc.
As far as communication within your app...
I always have a custom Application class that I register in the manifest. This way, when I have controllers and helpers that need to be a "single instance", I don't have to do all that crazy thread safe singleton stuff...I just keep one global copy of.
RoboGuice is a dependency injection framework that makes this even easier to accomplish...definitely worth looking into. If this interests you, the Google Group for RoboGuice is great and is constantly filled with the creators of the framework who can basically answer anything you need.
As far as in-app communication, I use my single instance Controller and State classes to hold state and do common tasks, and I usually use BroadcastIntents to communicate back to Activities from Services