I have written a benchmark method to get benchmark report on specific activity. My plan is to first do this portion properly. And then adding other operation like clicking on a button and test how frame timing metric works. As I have converted code into MVVM pattern so main goal is to compare with previous code.
Written method:
#get:Rule
val benchmarkRule = MacrobenchmarkRule()
#Test
fun startupEntryActivity() = benchmarkRule.measureRepeated(
packageName = "io.demo",
metrics = listOf(FrameTimingMetric()),
iterations = 5,
startupMode = StartupMode.COLD,
) {
pressHome()
val intent = Intent()
intent.setPackage("io.demo")
intent.action = "io.demo.views.splash.SplashIntroSelectionActivity"
startActivityAndWait(intent)
}
But its getting error in test. Its leaving me without any clue
Error: Activity not started, unable to resolve Intent { act=io.demo.views.splash.SplashIntroSelectionActivity flg=0x10008000 pkg=io.demo }
Need to know where its getting wrong or am doing it wrong
Related
I'm creating an Intent like so:
public void showThings(ArrayList<Thing> things) {
Intent intent = new Intent(this, ThingActivity.class);
intent.putExtra(THINGS, things);
startActivity(intent);
}
Then in the ThingActivity I want to get the ArrayList<Thing>
class ThingActivity {
var things: ArrayList<Thing>? = null
override fun onCreate(savedInstanceState: Bundle?) {
things = intent.extras.getSerializable(OtherActivity.THINGS) as? ArrayList<Thing>
}
Unfortunately, I can't seem to figure out how to cast to the appropriate type without triggering an "unchecked cast" warning. Is there a way to gracefully set to null if (somehow unexpectedly) the cast fails?
Appending ?: return null does not seem to work as I've seen suggested elsewhere
The unchecked cast warning is happening due to the way Java generics work at runtime. Because of type erasure, at runtime, the type of the list is just List, and not List<Thing>. That means that the cast is considered unsafe, even though it's quite possible for a human to look at the code and see that there's no problem.
While I agree with you that suppressing the warning isn't ideal, in this case I think it's fine.
The best solution, though, would be to implement the Parcelable interface on Thing. That way, when you want to pass a List<Thing> through an intent, you could write:
intent.putParcelableArrayListExtra(THINGS, things)
And when you want to read it back out:
things = intent.extras.getParcelableArrayListExtra(OtherActivity.THINGS)
Neither of these will cause a compiler warning.
As an alternative to Ben P's answer, you could use Gson.
Assuming that Things is simply a data class (holds a bunch of variables), this will work perfectly (this is also required by Ben P's answer).
Here's a way to implement it:
public void showThings(ArrayList<Thing> things) {
String json = new Gson().toJson(things);
Intent intent = new Intent(this, ThingActivity.class);
intent.putExtra(THINGS, json);
startActivity(intent);
}
Then you can get the ArrayList like this:
String json = intent.getStringExtra(THINGS);
TypeToken<ArrayList<Things>> token = new TypeToken<ArrayList<Things>>() {};
ArrayList<Things> things = new Gson().fromJson(json, token.getType());
Activity one:
val intent = Intent(this, SecondActivity::class.java)
val arrayGuide = ArrayList<Guide>()
intent.putParcelableArrayListExtra("arrayInfo",arrayGuide)
startActivity(intent)
Activity two:
if(intent != null){
val arrayList =
this.intent.getParcelableArrayListExtra<Guide>("arrayInfo")
}
fun kullaniciOlustur2(view: View){
val intent = Intent(applicationContext,KullaniciOlustur2::class.java)
intent.putExtra("input",makeUsername.text.toString())
intent.putExtra("input2",makeUserphone.text.toString())
startActivity(intent)
}
Mainactivity2 starts here..before this, I was using
val intent = intent
val received: String = intent.getStringExtra("input")
makeUsername.text = received
But this method doesn't work anymore.
I tried using getIntent() but couldn't get anything
val intent = getIntent()
Try this code
Activity 1
val intent = Intent(FirstActivity.this,SecondActivity::class.java) //not application context
intent.putExtra("input",makeUsername.text.toString())
intent.putExtra("input2",makeUserphone.text.toString())
startActivity(intent)
Activity 2
inside onCreate() method use
val stringOne = getIntent().getStringExtra("input")
Or more cleaner way is
val extras = getIntent().getExtras()
if (null != extras) {
val value = extras.getString("input")
//The key argument here must match that used in the other activity
}
and please check similar answers in Java, you may be able to get the Idea here already told in another answer.
I also Use Anko to remove this kind of boilerplate code
I recommend using Kotlin Anko, there are plenty of methods that will help you to remove this boilerplate code
check Anko Intents here
Use Below Code:
The Code is same as Java .Just difference is kotlin do not have
1. No semicolon at the end.
2. to call another activity kotlin use ::
ex.KotlinActivity::class.java
startActivity(Intent(this, KotlinActivity::class.java).putExtra("DataTrasfer", ""))
To Get Value:
intent.getStringExtra("DataTrasfer")
I have a 2 TextEdits on the screen. And they all have a OnFocusChangeListener which will check the text in the field, if it's empty it gonna set the error property to the error message. It works according to my ad-hoc test.
But I don't know how to verify this using Robolectric? I tried this:
#RunWith(RobolectricTestRunner::class)
class AuthLogDetailActivityUITest {
#Test
fun should_show_error_when_no_text_input_when_textInput_lost_focus() {
val logDetailsActivity = Robolectric.setupActivity(AuthLogDetailsActivity::class.java)
val quickNameTextEdit = logDetailsActivity.findViewById<TextInputEditText>(R.id.loginDetails_textEdit_quickName)
val passwordTextEdit = logDetailsActivity.findViewById<TextInputEditText>(R.id.loginDetails_textEdit_password)
quickNameTextEdit.performClick()
passwordTextEdit.performClick()
assertNotNull(quickNameTextEdit.error)
}
}
I tried to mimic the real world, where the user just click the text edit one by one without entering anything.
But in the real world, as soon as the user clicks the passwordTextEdit, quickNameTextEdit should show the error message.
But the test will always fail because the quickNameTextEdit.error is null.
I think it's not the way to trigger that onFocusChange event. What is the Robolectric way to test this behaviour?
I was able to get my OnFocusChangeListener triggering by using .performAccessibilityAction(ACTION_FOCUS, Bundle()). Hopefully this solves your problem. Your example would look like:
#RunWith(RobolectricTestRunner::class)
class AuthLogDetailActivityUITest {
#Test
fun should_show_error_when_no_text_input_when_textInput_lost_focus() {
val logDetailsActivity = Robolectric.setupActivity(AuthLogDetailsActivity::class.java)
val quickNameTextEdit = logDetailsActivity.findViewById<TextInputEditText>(R.id.loginDetails_textEdit_quickName)
val passwordTextEdit = logDetailsActivity.findViewById<TextInputEditText>(R.id.loginDetails_textEdit_password)
quickNameTextEdit.performAccessibilityAction(ACTION_FOCUS, Bundle())
passwordTextEdit.performAccessibilityAction(ACTION_FOCUS, Bundle())
assertNotNull(quickNameTextEdit.error)
}
}
Hello this is my first app with kotlin i am trying to make annual rate calculation app the problem is i have 4 activities every activity own button and edit's texts
i wan't when The User click the button, the program get the numbers from Edit's texts and only make the calculation and save it somewhere and same work for the activity 2 and 3.
but when he click the last button of the last activity i want to call all the results and show it in ViewText
The Question is:How to save data Every time somewhere and call when i need it?
First Activity
class st {
var int_P: Double? = null
var ctl_P: Double? = null
public constructor(int_P: Any, ctl_P: Any) {
this.int_P = int_P.toString().toDouble() //Physique
this.ctl_P = ctl_P.toString().toDouble()
public fun GetMP(): Double {
return (this.int_P!! + (this.ctl_P!! * 2)) / 3
}
}
Btn_Next1.setOnClickListener ({
var int_P = java.lang.Double.parseDouble(edit_IP.text.toString()) //Physique
var ctl_P = java.lang.Double.parseDouble(edit_CP.text.toString())
var ss = st(int_P,ctl_P)
val ic = Intent(this, Sec_Act::class.java)
startActivity(ic)
})
(Secend and Third Activity Same)
Activity 4
btn1.setOnClickListener ({
var act1 = MainActivity.st().GetMC()
Textv.text = act1.toString()
})
With this method i got problem (no value passed for parameter int_P , ctl_P)
There are many different ways to send information back to an Activity:
onActivityResult(),
having a singleton class,
use Shared Preferences,
headless fragments,
sqlite database,
store the information in a file.
Intents
receivers
You need to determine which will be the best solution for you. Whether it's kotlin or java, the methodology will be the same.
We currently have an Android application that we are testing with Espresso. One of the features we want to test is selecting a picture/image from the local image gallery. We can get all the way to bringing up the Gallery view, but then cannot select from Recent, Downloads, Gallery in the resulting window. A snippet as to how we got as far as we did is included below.
public void testShouldBeAbleToSelectPhotoFromGallery() {
getActivity();
// given
onView(withId(launch_gallery_button)).perform(click());
onView(withText("Gallery")).perform(click()); // this is a button in our app
// then we get stuck :(
}
Thanks!
This is not possible with with either Robotium or Espresso, as they only work on Activities of the app under test.
To write integration tests that work across different apps and Android built-in apps, you can use the UiAutomator framework provided by Google.
Basically you would analyse the gallery app in the uiautomatorview to learn how to select the ui elements your test case needs and then act on them, not unlike Espresso.
If you want to test that functionality in your app you should use the intent mocking functionality in Espresso.
Espresso tests should not leave your app in the first place.
Instead you catch the intent you use to open the gallery app and return a result back to your app.
During the test you will stay in your app, you will get a result immediately.
To do this check the intending and intended api's of Espresso.
Here is a tutorial by Pengj to get you acquainted with intent mocking. The tutorial mentions Mockito but you can perfectly use this without it.
The best and proper way is to use Espresso Intents. So you need to add the dependency in your app's build.gradle
androidTestImplementation "androidx.test.espresso:espresso-intents:$espressoVersion"
In my case I was openning the gallery from a button within my app, then the code for the test and the addition of the intending and intended api's of Espresso as follows:
#Test
fun photos_CreationGalleryClickUI() {
savePickedImage()
val imgGalleryResult = createImageGallerySetResultStub()
intending(hasAction(Intent.ACTION_CHOOSER)).respondWith(imgGalleryResult)
onView(withId(R.id.photos_button_gallery)).perform(click())
onView(withId(R.id.photos_bigimage_viewer)).check(matches(hasImageSet()))
}
Here the matcher for intending is the key when the gallery needs to be open and avoid to manually pick an image:
hasAction(Intent.ACTION_CHOOSER)
I' using two helpers:
savePickedImage() to mock an image from the gallery
private fun savePickedImage() {
val bm = BitmapFactory.decodeResource(mActivityTestRule.activity.resources, R.mipmap.ic_launcher)
assertTrue(bm != null)
val dir = mActivityTestRule.activity.externalCacheDir
val file = File(dir?.path, "myImageResult.jpeg")
System.out.println(file.absolutePath)
val outStream: FileOutputStream?
try {
outStream = FileOutputStream(file)
bm.compress(Bitmap.CompressFormat.JPEG, 100, outStream)
outStream.flush()
outStream.close()
} catch (e: FileNotFoundException) {
e.printStackTrace()
} catch (e: IOException) {
e.printStackTrace()
}
}
And createImageGallerySetResultStub to stubbing the result after "picking" the image. Here putting the result as an array of parcelables was key, without it, the never result was never recognized:
private fun createImageGallerySetResultStub(): Instrumentation.ActivityResult {
val bundle = Bundle()
val parcels = ArrayList<Parcelable>()
val resultData = Intent()
val dir = mActivityTestRule.activity.externalCacheDir
val file = File(dir?.path, "myImageResult.jpeg")
val uri = Uri.fromFile(file)
val myParcelable = uri as Parcelable
parcels.add(myParcelable)
bundle.putParcelableArrayList(Intent.EXTRA_STREAM, parcels)
resultData.putExtras(bundle)
return Instrumentation.ActivityResult(Activity.RESULT_OK, resultData)
}
hasImageSet() as a matcher helper that checks if the imageView has or not a drawable:
return item.getDrawable() == null
NOTE: Remember to set the grant rule to avoid problems with the permissions and to define your test rule as an IntentTestRule (which extends from ActivityTestRule already)
#get:Rule
var mActivityTestRule = IntentsTestRule(AuctionCreationActivity::class.java)
#get:Rule
var mRuntimePermissionRule = GrantPermissionRule.grant(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
The dependency:
androidTestImplementation "androidx.test:rules:$testRules"