Butterknife + Espresso NoMatchingViewException - android

Can Butterknife work with Espresso? I have a test sample, there are 2 activities. In the first activity I print the text, than click the button and send text to another activity. After that I created MainActivityTest and everything worked well. But when I started to use Butterknife I caught the error NoMatchingViewException.
My first activity:
public class MainActivity extends AppCompatActivity {
public static final String TAG = MainActivity.class.getSimpleName();
#BindView(R.id.first_text)
EditText mEditText;
#OnClick(R.id.button_one)
public void click(){
Intent intent = new Intent(MainActivity.this,SecondActivity.class);
intent.putExtra("TEXT",mEditText.getText().toString());
startActivity(intent);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
The second activity:
public class SecondActivity extends AppCompatActivity {
public static final String TAG = SecondActivity.class.getSimpleName();
#BindView(R.id.second_text)
TextView mTextView;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
}
#Override
protected void onResume() {
super.onResume();
if(getIntent().getStringExtra("TEXT")!=null) {
mTextView.setText(getIntent().getStringExtra("TEXT"));
}
}
}
My MainActivityTest:
public class MainActivityTest {
#Rule
public ActivityTestRule<MainActivity> mActivityRule = new ActivityTestRule<>(
MainActivity.class);
#Before
public void setUp() throws Exception {
}
#Test
public void onCreate() throws Exception {
onView(withId(R.id.first_text)).perform(typeText("Test"));
onView(withId(R.id.button_one)).perform(click());
onView(withId(R.id.second_text)).check(matches(withText("Test")));
}
}

Related

Application static property is null

I instantiate a static property at the beginning of Activity's onCreate(), but some of my users get NullpointerException when I try to get it in MainActivity.
In my opinion, you code should be
public class TestActivity extends AppCompatActivity {
public static String mValue;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
mValue = "my_value";
}
}
The value TestActivity.mValue should be null util the onCreate executes.You can init the mValue like this
public class TestActivity extends AppCompatActivity {
public static String mValue;
static {
mValue = "my_value";
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
}

Can setContentView be replaced by android-annotations when espresso is used?

I have espresso test which verifies that text is displayed:
public class InformationActivityTests {
#Rule
public ActivityTestRule<InformationActivity_> mInformationActivityTestRule =
new ActivityTestRule<InformationActivity_>(InformationActivity_.class) {
#Override
protected Intent getActivityIntent() {
Intent i = new Intent(getTargetContext(), InformationActivity_.class);
i.putExtra("INFORMATION", "Espresso");
return i;
}
};
#Test
public void textIsDisplayed() {
onView(withText("Espresso")).check(matches(isDisplayed()));
}
}
This test passes when Activity has following code:
#EActivity
public class InformationActivity extends AppCompatActivity {
#ViewById(R.id.information_view)
TextView informationView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_information);
Intent intent = getIntent();
String information = intent.getStringExtra("INFORMATION");
informationView.setText(information);
}
}
but fails when I "move" setContentView to #EActivity annotation:
#EActivity(R.layout.activity_information)
public class InformationActivity extends AppCompatActivity {
#ViewById(R.id.information_view)
TextView informationView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent intent = getIntent();
String information = intent.getStringExtra("INFORMATION");
informationView.setText(information);
}
}
Error is:
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.edu/com.edu.InformationActivity_}: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.TextView.setText(java.lang.CharSequence)' on a null object reference
Am I doing something wrong or is it an issue with espresso / android-annotations?
I've checked code generated by android-annotations when using #EActivity(R.layout.activity_information) and this is how onCreate looks like in generated class (InformationActivity_):
public void onCreate(Bundle savedInstanceState) {
OnViewChangedNotifier previousNotifier = OnViewChangedNotifier.replaceNotifier(onViewChangedNotifier_);
init_(savedInstanceState);
super.onCreate(savedInstanceState);
OnViewChangedNotifier.replaceNotifier(previousNotifier);
setContentView(R.layout.activity_information);
}
the problem is that it first calls super.onCreate (so onCreate from InformationActivity) where I handle intent and TextView and then it calls setContentView and this can't work like that.
The solution for this is what Be_Negative suggested, so using #AfterViews annotation. It also simplifies code a bit (I could remove onCreate method):
#EActivity(R.layout.activity_information)
public class InformationActivity extends AppCompatActivity {
#ViewById(R.id.information_view)
TextView informationView;
#AfterViews
void handleIntent() {
Intent intent = getIntent();
String information = intent.getStringExtra("INFORMATION");
informationView.setText(information);
}
}
Your problem is that you are never initializing informationview
public class InformationActivity extends AppCompatActivity {
#ViewById(R.id.information_view)
TextView informationView; //<-- Null
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent intent = getIntent();
String information = intent.getStringExtra("INFORMATION");
informationView.setText(information); //<--STILL NULL
}
}
So you first will have to initialize that view.

Find Id of View in Child Activity

I have an issue , need your help , my question is : I have a multiple activity , so i have created one abstract class which hold the view . Now my question i am able to pass the view to the Base Activity but how to finds view id in Child Activity Class.
I Tried like this :
public abstract class BaseActivity extends Activity {
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(getLayoutResourceId());
}
public abstract int getLayoutResourceId();
}
My Activity Class:
public class ServiceActivity extends BaseActivity {
Button startSerice_btn, stopService_btn;
MyService myService;
#Override
public int getLayoutResourceId() {
return R.layout.service_xml;
}
}
You can access your views after the super.onCreate() call in the ServiceActivity:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Access them here
}
I think you no need to set content view in BaseActivity like below :
public abstract class MyAppBaseActivity extends AppCompatActivity implements View.OnClickListener {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
}
And you just extends Activity like below :
// for MyCustomActivity1
public class MyCustomActivity1 extends MyAppBaseActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
#Override
public void onClick(View view) {
}
}
// for MyCustomActivity2
public class MyCustomActivity2 extends MyAppBaseActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
#Override
public void onClick(View view) {
}
}

Put common listeners inside MainActivity class

Im interested if i can to set some common listeners inside main activity class? For my project i use FirebaseAuth, so i would like to init it in MainActivity onCreate(), setup needed listeners in onStart() and onStop(), and then inherit that class in every other activity class.
Some code to please you :]
MainActivity class [parent]:
public class MainActivity extends AppCompatActivity {
private static final String TAG = MainActivity.class.getSimpleName();
protected FirebaseAuthentication firebaseAuthentication;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
firebaseAuthentication = new FirebaseAuthentication(FirebaseAuth.getInstance(), FirebaseDatabase.getInstance());
}
#Override
protected void onStart() {
super.onStart();
firebaseAuthentication.addAuthStateListener();
}
#Override
public void onStop() {
super.onStop();
firebaseAuthentication.removeAuthStateListener();
}
}
AuthActivity class [child]:
public class AuthActivity extends MainActivity implements FirebaseAuthentication.OnUserAuthListener {
#BindView(R.id.viewPager) LockableViewPager viewPager;
private String userUID;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_market);
ButterKnife.bind(this);
firebaseAuthentication.setOnUserAuthListener(this);
firebaseAuthentication.isSingedIn(); // check if user is singed in
}
#Override
// response for firebaseAuthentication.isSingedIn() above
public void onAuthSuccess(String userUID) {
this.userUID = userUID;
}
#Override
// response for firebaseAuthentication.isSingedIn() above
public void onAuthFailure(String message) {
snackbar(message);
Intent intent = new Intent(this, AuthActivity.class);
startActivity(intent);
finish(); // TODO mb should to delete it
}
}
Can this implementations bring me errors (maybe NullPointerExeption or what unexpectedly in future)?
Would be great if you provide me some sources to read/watch.
Thank you.
Perfect example of abstraction, but not really a question.
You will not get any nullpointers or other errors by implementing it like this.

Mocking method before activity is created?

I am using Espresso and Mockito for testing an Activity. Is it possible to mock a method before an activity is created.
public class MyActivity extends Activity {
public int i;
#Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
callSomeMethod();
callAnotherMethod();
}
protected void callSomeMethod() {
//do some work
}
protected void callAnotherMethod() {
//do some work
}
}
My test class looks like
public class ActivityTest{
#Rule
public MyActivityRule testRule = new MyActivityRule(MyActivity.class);
public void test_preconditions(){
assertNotNull(testRule.getActivity())
}
}
But i need to mock callSomeMethod() and callAnotherMethod() method. Thanks in advance.

Categories

Resources