I'm using the newer way to instantiate Android's UiAutomator that utilizes the InstrumentationRegistry to retrieve the context. The problem is that the new methodology for automation doesn't extend UiAutomatorTestCase or any set of classes that can pass parameter to retrieve via getParams() in other tests. I tried making static variables but they seem to reset after each case.
I was wondering what the newer methodology of adding retrievable parameters was? I also can't seem to find a dupe question which is why I'm posting this...
EDIT:
As another note to the original question, this is a completely automated test suite that has nothing to do with our main application. It still uses the standard UI automator functionality but is a separate code project.
So basically I'm just looking to store results from one #Test scenario to the next #Test scenario that runs in succession.
Thank you
You should use InstrumentationRegistry.getArguments(). It returns the same Bundle of command line arguments as UiAutomatorTestCase.getParams().
Related
I'm writing data driven testing of my android app, and have begun writing a CSV to espresso testing framework which will allow me to quickly design and alter tests. Espresso can verify basic things about the UI such as successful clicks and text entry, but can it handle more advanced logic?
For example, I'm attempting to create a receipt based on some clicks that are made during the test. This will have been costed before runtime and entered into the CSV for automatic comparison of actual vs expected outcomes. In order to do this, I will need to access the receipt object to check its values? Or at least the textbox which displays it (easy, but not really what I'm after).
So, is there any way to get objects stored in memory from the main application into the espresso testing framework?
Found the answer to my question.
In order to get to any objects/variables, you need to get to a class in which they exist. This is achieved in espresso with the #Rule tag:
#Rule
public ActivityTestRule<MainActivity> mainActivityTestRule = new ActivityTestRule<MainActivity>(MainActivity.class);
From here you can do:
mainActivityTestRule.getActivity();
and from there all objects can be accessed
EDIT:
Primitives seem to come through fine, but I'm still trying to confirm if objects are actually passed through. It seems that the objects that are in my Espresso class are default, as though the constructor has just been run. Will update with more info.
Edit 2:
This does NOT work for objects. Putting a break-point in the espresso class and one in the main application and comparing them shows different object IDs. Getting the object from the main application doesn't return the object in the same state.
I have an android app that uses ORMLite/SQLite and I use Robolectric in conjunction with JUnit 4 to allow me to run unit tests in Android Studio and on a Jenkins build server.
Typically I would setup test data in my tests, in the setup, and then run my test scenarios against it but when I tried to do this I started getting issues and exceptions which seemed to be related to files being locked or something and that seems to be a problem others have had... so what I have done up until now is use the create database method in my database helper to create some dummy data which the tests expect to be there.
The problem is my application now needs to plug into a real database and I can't have it setup dummy data when it runs.
If there a way, within my database helper class, to detect if the code is executing on a device or within Robolectric?
This is what works well for me on Robolectric 3.
public static boolean isRoboUnitTest() {
return "robolectric".equals(Build.FINGERPRINT);
}
To start with, I'll say that you shouldn't be putting code to initialise dummy/test data in the normal releasable code and in general you shouldn't need to know from the main app if you're in a robo run or not.
Now moving past the disclaimer and to actually answer your question... One way you could to this is to have a method in your application class like this
public boolean isRoboTestRun() {
return false;
}
Then create a "TestApplication" in the test package that extends your normal application and overrides this method to return true.
It's hacky, but that's because it's not really meant to work that way :)
At some point you have to init OrmLiteSqliteOpenHelper with your Context.
Let assume you do this in your application class in onCreate. So just create Test<your application class name> in your tests sources and override onCreate with empty implementation.
Robolectric will find this class and will use during the tests. More details here.
I'm trying to write a batched instrumentation test (using ActivityInstrumentationTestCase2) for a particular Activity where I change the intent each time the test runs. I can do this with a single test, and just loop through stopping and restarting the Activity with the new intent, but this is not what I want. One reason is they really should be separate test runs. The other reason is, I'm using Spoon to generate a report when the tests finish, and the report will rightly think I only ran one test.
What I would like is it to treat a single test as a possibly infinite number of tests, and pass the data into the test each time the test runs.
Unfortunately you can't use Theories because it results in a RuntimeException where the InstrumentationTestRunner can't find my tests. Anyone have any luck with this?
You could always just create a "testing" intent. In order to simulate the relaunching of the application, make a method or several methods that reset all your static variables between tests. Then you can test the classes from within a testing intent inside the application itself using
assert("value", MyClass.myMethod);
resetStatics();
assert(true, MyClass,myMethod);
resetStatics();
I don't know how much this will help you, if at all, but this is how I started writing my own tests.
I recently discovered that you can add a public static Test suite() method to a test class, and when you run just this single test class, InstrumentationTestRunner will run the Test returned by this method. This is helpful because suite() can explicitly call any constructor of your TestCase, including one with parameters.
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()
I would like to make some automatic UI tests for my Android application using recomended approach ( http://developer.android.com/tools/testing/index.html ). My activity fetches data from server and after getting response it modifies some UI elements. I want to check whether UI is modified properly but I also want to test this issue without connecting to server. I thought about providing mock component instead of object which connects to server on behalf of activity. But how could I in my test cases tell acivity to replace original object with mock object? Do you know any good approches?
I thought about putting a special flag in Intent using setActivityIntent (indicating that mock object should be used) before calling getActivity in my ActivityInstrumentationTestCase2 instance.
But this approach requires adding some if statements in application code what makes code less clear and more complicated.
Do you have any better suggestions? Thanks in advance.