During my unit Tests I want to basically test if an Activity is started by a simple pressure on a button, that is in an HorizontalListView. I've already succeed in starting new Activities during previous unit test but this one is not acting as wanted. I've got an assertion failure telling me that the activity that I want to start is still null.
Actually, when I launch my unit test, it seems to not perform the click. I have to perform it myself during the test by using my little finger for the test to pass.
To see if I was clicking on the right View I used Logs to see which view my test was clicking and which I actually want to click: and it seems to be the right view (the right Id, the right Position and the right View). So i think the problem isn't where I'm clicking.
The Activity i'm testing is called StudioActivity and the Activity i want to start is called AddBoasterActivity.
My Unit test method:
public void testSwitchToAddBoaster(){
assertTrue(mBoasterPreviewFragment.getWithAddButton());
ActivityMonitor activityMonitor = getInstrumentation().addMonitor(AddBoasterActivity.class.getName(), null, false);
mStudioActivity.runOnUiThread(new Runnable() {
#Override
public void run(){
int lPosition = mBoasterPreviewFragment.getAdapter().getCount()-1;
View lView = mBoasterPreviewFragment.getBoaster().getChildAt(lPosition);
//HERE ARE LOGS TO SEE IF MY TEST IS PERFORMING
//THE CLICK ON THE RIGHT VIEW AT THE GOOD POSITION
Log.i("TEST POSITION:", ""+lPosition);
Log.i("TEST ID: ",""+lView.getId());
Log.i("TEST VIEW: ", ""+lView);
//AND IT'S THE GOOD VIEW!
mBoasterPreviewFragment.getBoaster().performItemClick(lView,lPosition,lView.getId());
}
});
AddBoasterActivity lAddBoasterActivity = (AddBoasterActivity) getInstrumentation().waitForMonitorWithTimeout(activityMonitor,5000);
assertNotNull(lAddBoasterActivity); //HERE IS THE FAILURE, THE ACTIVITY HASN'T BEEN STARTED
mWFBoasterPreviewFragment = new WeakReference<BoasterPreviewFragment>((BoasterPreviewFragment) lAddBoasterActivity.getSupportFragmentManager().findFragmentById(R.id.fragment_preview));
mBoasterPreviewFragment = mWFBoasterPreviewFragment.get();
assertNotNull(mBoasterPreviewFragment);
lAddBoasterActivity.finish();
}
The OnItemClickListener:
mBoaster.setAdapter(mAdapter);
if (withAddBoasterButton) {
mBoaster.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if (position == mAdapter.getCount() - 1) {
//HERE IS THE CURRENT VIEW
Log.i("POSITION:", ""+position);
Log.i("ID: ",""+id);
Log.i("VIEW: ", ""+view);
Intent intent = new Intent(getActivity().getApplicationContext(), AddBoasterActivity.class);
intent.putExtra(AddBoasterActivity.EXTRA_BOASTER_SELECTED, mSelectedUsers);
intent.putExtra(AddBoasterActivity.EXTRA_IS_STREAM, isStream);
startActivityForResult(intent, AddBoasterActivity.REQUEST_CODE_ACTIVITY);
}
}});
}
Performing manually a click is quite embarrassing for tests which have to be automated. So if someone has any idea why it is acting like this.
Thanks for the help!
Well I finally found it... just a night to sleep and it was okay. I should have think about it earlier, but Robotium already helped me a few times ago.
Check it out if you haven't test it yet: https://code.google.com/p/robotium/
So here's how it looks like with Robotium:
public void testSwitchToAddBoaster(){
Solo solo = new Solo(getInstrumentation(), getActivity());
getInstrumentation().waitForIdleSync();
ActivityMonitor activityMonitor = getInstrumentation().addMonitor(AddBoasterActivity.class.getName(), null, false);
assertTrue(mBoasterPreviewFragment.getWithAddButton());
int lPosition = mBoasterPreviewFragment.getAdapter().getCount()-1;
View lView = mBoasterPreviewFragment.getBoaster().getChildAt(lPosition);
solo.clickOnView(lView); //SIMPLE CLICK
AddBoasterActivity lAddBoasterActivity = (AddBoasterActivity) getInstrumentation().waitForMonitorWithTimeout(activityMonitor,5000);
assertNotNull(lAddBoasterActivity); //NOW THE ACTIVITY IS STARTED
mWFBoasterPreviewFragment = new WeakReference<BoasterPreviewFragment>((BoasterPreviewFragment) lAddBoasterActivity.getSupportFragmentManager().findFragmentById(R.id.fragment_preview));
mBoasterPreviewFragment = mWFBoasterPreviewFragment.get();
assertNotNull(mBoasterPreviewFragment);
lAddBoasterActivity.finish();
}
Related
I want to implement this
.
I want to check if the clicked item is fully visible and if it's not I would like to smoothly scroll upwards/downwards. I have a GridLayoutManager with 3 columns. The items are all of the same size, and are just ImageViews.
I am able to get the RecyclerView to scroll with:
#Override
public void onClick(View view) {
int adapterPosition = RecHolder.this.getAdapterPosition();
mRecyclerView.scrollToPosition(adapterPosition);
...
}
But it's not a "scroll", it's very laggish and way too quick.
If I try to use mRecyclerView.smoothScrollToPosition(adapterPosition); the result is the same. Exactly the same movement, there is no visible difference.
Don't bother testing to see if it's not completely visible. Just insert a command to scroll to that position. Since you didn't post any of your code I can't specifically say how you would do it. I personally have my adapter create an intent and my activity handles the intent. If that's what you're doing then you can include the getAdapterPosition() as an extra like this (vh is my ViewHolder).
vh.mImageView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
SelectItemGridAdapter.ContentViewHolder vh = (SelectItemGridAdapter.ContentViewHolder) (((View)v.getParent()).getTag());
Intent intent = new Intent(ACTION_SELECT_Item);
intent.putExtra(Constants.MSG_TYPE, SELECT_ITEM_TAPPED);
intent.putExtra(SELECT_ITEM_TAPPED_ID, vh.viewModel.mItemId);
intent.putExtra(SELECT_ITEM_TAPPED_POS, vh.getAdapterPosition());
LocalBroadcastManager.getInstance(mContext).sendBroadcast(intent);
}
});
Then the reveiver in the activity can get the SELECT_ITEM_TAPPED_POS value...
int pos = intent.getIntExtra(SelectItemGridAdapter.SELECT_ITEM_TAPPED_POS, -1);
if (pos > -1)
rv.scrollToPosition(pos);
HTH, Mike
So after calling this onto my tests to layout the recyclerview:
recyclerView.addOnItemTouchListener(listener);
recyclerView.measure(0, 0);
recyclerView.layout(0, 0, 100, 10000);
and my OnItemTouchListener being:
listener = new RecyclerOnTouchListener(this, new RecyclerOnTouchListener.OnItemClickListener() {
#Override
public void onItemClick(View v, int position) {
Toast.makeText(this, "Sample toast", Toast.LENGTH_SHORT).show();
}
});
and I want to assert:
Assertions.assertThat(ShadowToast.getTextOfLatestToast()).isEqualToIgnoringCase("Sample Toast");
I need to simulate item clicks on the recyclerview. And what i'm doing is this:
recyclerView.findViewHolderForAdapterPosition(0).itemView.performClick();
recyclerView.performClick()
and they both return false, meaning no onclick listener in them is being called.
So how do we really test OnItemTouchListener in recyclerview? In Robolectric?
Any help would be appreciated. Thanks!
I had a similar issue that was fixed by adding the line before setAdapter:
recyclerView.setLayoutManager(LinearLayoutManager(this))
I've run in to the same problem and while I haven't found any good solution to the problem, I have a workaround that at least makes testing possible until I can find something better.
One thing you can do is to create a method in your activity and have the onClick listener call that directly.
void recyclerOnClick(View view, int position) {
Toast.makeText(this, "Click", Toast.LENGTH_SHORT).show();
}
void addTouchListener() {
RecyclerOnTouchListener touchListener = new RecyclerOnTouchListener(this, recyclerView,
new RecyclerOnTouchListener.OnItemClickListener() {
#Override
public void onClick(#NotNull View view, int position) {
recyclerOnClick(view, position);
}
});
recyclerView.addOnItemTouchListener(touchListener)
}
Then in your tests you can just call adapter.recyclerOnClick() for the view you want to simulate the click on.
I made this application go from one activity to the next. and then come back, but after it comes back to my main activity the button to go to the next view again does not do anything? I thought it was from startActivityForResult but I did it a different way and its still not working...
Here is some code: if button is pushed
if (search.isPressed() && searchPressed == false) {
// show search list
switch1 = new Intent(MainActivity.this, SearchActivity.class);
// startActivityForResult(switch1, 0);
startActivity(switch1);
}
in next activity:
private OnItemClickListener listListener = new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
String text = (String) ((TextView) arg1).getText();
String[] selected = text.split(" - ");
selected[0] = selected[0].replace(' ', '_');
Log.w("COMPANY", selected[0]);
Log.w("PART", selected[1]);
// Intent data = new Intent(SearchActivity.this,
// MainActivity.class);
// data.putExtra("key", selected);
// setResult(RESULT_OK, data);
MainActivity.searchData = selected;
finish();
// startActivity(switch2);
}
};
////\ when item is pushed it goes back to main screen
My guess from what you've posted so far is that you are actually having trouble because of the if statement, not the startActivity().
Try putting a log output inside this if statement:
if (search.isPressed() && searchPressed == false) {
Log.d(TAG, "Search has been pressed");
// show search list
switch1 = new Intent(MainActivity.this, SearchActivity.class);
// startActivityForResult(switch1, 0);
startActivity(switch1);
}
If you don't see your out put in the log cat then the problem is with the if statement. If you post some more of the code from around this if I can try to help figure it out for you. But it seems like your condition is contradicting. To me it looks like you are checking to see if search is both pressed and not pressed.
Post a bit more of the MainActivity code, especially where the searchPressed boolean gets set.
One of the two conditions in your first part of the code will fail after the first time.
So either condition
search.isPressed()
or condition
searchPressed == false
is not true
i have made one of these tap number games for android as a test project and for this i have made a gridview with about 20 buttons in it. when one of these buttons is pressed an animation is started. this runs fine for the first few times but than becomes slower and starts stuttering.
i assume it has something to do with the animation ressource as i use it several times at the same time but i dont know how to solve the problem.
as i want to remove the button from the gridview when the animation ends i wrapped the AnimationDrawable class to be able to set a Handler which is called at the end of the animation.
public void animate() {
setBackgroundResource(R.drawable.myanimation);
final AnimationDrawable anim = (AnimationDrawable) getBackground();
final BetterAnimationDrawable better = new BetterAnimationDrawable(anim);
better.setEndHandler(new EndHandler());
better.start();
}
thanks in advance
UPDATE:
#warpzit: thanks for your answer. it's not a handler for earch click but a handler for each button. the onclick method disables the button (so it can only be pressed once) and then calls animate(). actually theres not much more code i can post, the gridview adapters getView looks like this:
#Override
public View getView(final int position, final View convertView, final ViewGroup parent) {
final MySpecialButton sb = new MySpecialButton(getApplicationContext());
sb.setOnClickListener(new SpecialButtonClickListener());
return nv;
}
and the mentioned handler looks like this (its actually not removing the button but changing the background-drawable, sorry for that):
private class MySpecialHandler extends Handler {
public MySpecialHandler() {
}
#Override
public void handleMessage(final Message msg) {
super.handleMessage(msg);
final Bitmap bitmapMask = BitmapFactory.decodeResource(getResources(), R.drawable.aspecialmask);
final BitmapDrawable d = new BitmapDrawable(bitmapMask);
d.setColorFilter([someColor], Mode.MULTIPLY);
setBackgroundDrawable(d);
}
};
You make a new handler for each click? That gotta hurt... How about making just 1 for each button or something else far smarter (need to see more code to come with other suggestions).
I have a LinearLayout that contains some other views and among those a ListView.
This view is loaded from another one by clicking a button.
This button somehow specify what element in the ListView needs to be the first visible one in the list. The elements that populates the list are retrieved via HTTP from an external server.
The problem is that I can get the Nth element to be the first in the list.
Please note, I do not want to move it form it current position to a new one, I want the list to scroll.
I have tried with setSelected() and scrollTo(x,y) and scrollBy(x,y) but with no luck.
I have also gave a try to this pice of code, as ugly as it is, but I just wanted to try f it was working:
ListView categoryList = (ListView)findViewById(R.id.category_list);
categoryList.post(new Runnable() {
#Override
public void run() {
Log.d(this.getClass().getName(), "CategoryActivity.scrollToIndex: " + CategoryActivity.scrollToIndex);
if(CategoryActivity.scrollToIndex>0){
ListView categoryList = (ListView)findViewById(R.id.category_list);
categoryList.setScrollContainer(true);
categoryList.scrollTo(4, CategoryActivity.scrollToIndex * 50);
categoryList.requestLayout();
}
}
});
And this gave me some success, but the ListView was then behaving crazy in a way I am not even able to describe....
Any idea?
Try to add it to the message queue
categoryList.post(new Runnable() {
public void run() {
categoryList.scrollTo(4, CategoryActivity.scrollToIndex * 50);
}
});
It worked for me in a ScrollView (check this answer).
i made functions that could be useful for others for listview scrolling, they work for me in every android version, emulator and device, here itemheight is the fixed height of view in the listview.
int itemheight=60;
public void scrollToY(int position)
{
int item=(int)Math.floor(position/itemheight);
int scroll=(int) ((item*itemheight)-position);
this.setSelectionFromTop(item, scroll);// Important
}
public void scrollByY(int position)
{
position+=getListScrollY();
int item=(int)Math.floor(position/itemheight);
int scroll=(int) ((item*itemheight)-position);
this.setSelectionFromTop(item, scroll);// Important
}
public int getListScrollY()
{
try{
//int tempscroll=this.getFirstVisiblePosition()*itemheight;// Important
View v=this.getChildAt(0);
int tempscroll=(this.getFirstVisiblePosition()*itemheight)-v.getTop();// Important
return tempscroll;
}catch(Exception e){}
return 0;
}