I have a simple activity with only one edittext which was set to "http://" in xml. Based on google tutorial, I wrote some unit tests for status check. I want to practice unit test and pass all tests. But I cannot pass testStateDestroy() and testStatePause() (log shows mUrlView=="changed"). The code below is very easy, did I miss something? Thank you in advance.
public class MainActivity extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
public class MainActivityTest extends ActivityInstrumentationTestCase2<MainActivity> {
private Activity mActivity;
private EditText mUrlView;
public MainActivityTest() {
super("au.com.crystalfish.safeshare.activity", MainActivity.class);
}
protected void setUp() throws Exception {
super.setUp();
mActivity = this.getActivity();
mUrlView = (EditText) mActivity.findViewById(au.com.crystalfish.safeshare.R.id.url);
}
public void testPreconditions() {
assertNotNull(mActivity);
assertEquals(mUrlView.getText().toString(), "http://");
}
#UiThreadTest
public void testRotate() {
mUrlView.setText("changed");
mActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
mActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
assertEquals(mUrlView.getText().toString(), "changed");
}
#UiThreadTest
public void testStateDestroy() {
mUrlView.setText("changed");
assertEquals(mUrlView.getText().toString(), "changed");
mActivity.finish();
mActivity = this.getActivity();
assertEquals(mUrlView.getText().toString(), "http://"); <===========should be "http://" since it is a new activity
}
#UiThreadTest
public void testStatePause() {
Instrumentation mInstr = this.getInstrumentation();
mInstr.callActivityOnPause(mActivity);
mUrlView.setText("changed");
mInstr.callActivityOnResume(mActivity);
assertEquals(mUrlView.getText().toString(), "http://");<======should be "http://" since the text should bot be changed when the activity was paused
}
}
Well, for your testStatePause() test I think that may be valid. Even if the activity is paused you are still free to modify it however you want since you still have a reference to it (or one of its textViews at least. In a test like this, you should change the value of the textView in the actual activity's onPause method, then use your testStatePause test to verify that onPause was called and did its job correctly, then do the same for onResume().
I'm not really familiar with Android's testing framework but maybe a similar issue is happening with your testStateDestroy() test. Your mUrlView could still be pointing to the old, finished Activity. The old activity is no longer valid but its widgets might be.
Related
I was developing an exam score calculator app.
When I want to call AD methods,advertisements don't show up.
Calculation process happens in OnCreate method:
public class resultActivity extends AppCompatActivity {
public String responseId;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_result);
/*Calculation...*/}
and other voids like:
public void requestAd() {
/*AD RQUESTING PROCESS...*/
}
and
public void showAd() {
/*AD SHOWING PROCESS...*/
}
AD team gave me this code to call the method and it works well:
requestButton.setOnClickListener(v -> requestAd());
showButton.setOnClickListener(v -> showAd());
But the Problem is I don't have buttons to call them so I tried this:
public class resultActivity extends AppCompatActivity {
public String responseId;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_result);
requestAd();
showAd();
/*Calculation...*/}
But when the activity starts ads don't show up!
The whole question is I want this methods to be called while this activity starts.
thank you.
Try building up the release version APK and test on it. Maybe your Ad-provider have some restrictions in debug version?
I made another class and moved request Ad and showAd there. Then, I made an object and called the method through object.
I have to mention that I changed a minor thing in requestAd but the main job was done by the object.
Thank You All.
In this question some years ago someone suggested unit-testing a startService call by using a specific Context.
Now, about 4 years later, I am wondering if this functionality can't be handled by some Framework like Espresso.
I have an intentservice:
public class MyService extends IntentService {
#Override
protected void onHandleIntent(Intent intent) {
if (/* condition */) {
/* do Something short-lasting */
}
return;
}
My code starts a service in onCreate()
public class ListActivity extends SomeActivityClass {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
startService(new Intent(this, MyService.class));
}
My testcode expects the service to be started:
#RunWith(AndroidJUnit4.class)
public class ListActivityTest {
#Rule
public final ActivityTestRule<ListActivity> rule
= new ActivityTestRule<ListActivity>(ListActivity.class, true, false);
#Test
public void test_startService() {
Intents.init();
Context targetContext = InstrumentationRegistry.getTargetContext();
Intent showListIntent = new Intent(targetContext, ListActivity.class);
rule.launchActivity(showListIntent);
Intents.intended(IntentMatchers.hasComponent(MyService.class.getName()));
Intents.release();
}
}
My problem is, that it seems that the launch of the ListActivity is done but the framework does not wait for the intent to start the service to be issued.
I've tried to use an IdlingResource, but that means that i would have to add test code to production code, which i don't want to do, obviously: The IntentService i want to start is a short running piece of code, so recording some state about wether the IntentService is running or has ended already to return it to the IdlingResource callback is not an option.
Any hints how to check the startService call?
EDIT
Well, it seems that Robolectric can achieve exactly what i wanted using shadows.
I want to access multiple Activity in my Instrumental testing.
e.g Login -> Search-> Listing-> Detail Activity
I have achieved till 'Listing activity' but i want to go for Listing Activity Element[1]'s Detail page.
Below is my code for
#RunWith(AndroidJUnit4.class)
public class ContactSearchScreeenTest extends ActivityInstrumentationTestCase2<ContactSearchScreen> {
public ContactSearchScreeenTest() {
super(ContactSearchScreen.class);
}
#Rule
public ActivityTestRule<ContactSearchScreen> mActivityRule =
new ActivityTestRule<>(ContactSearchScreen.class);
#Override
protected void setUp() throws Exception {
super.setUp();
}
#Test
public void sendToSearchResultActivity()
{
onView(withId(R.id.etSearchName))
.perform(typeText("ssasa"), pressKey(KeyEvent.KEYCODE_SEARCH));
GlobalClass globalVariable = (GlobalClass) mActivityRule.getActivity().getApplicationContext();
globalVariable.setSearchStr("ssasa");
mActivityRule.getActivity().callForNextSearchActivity();
}
}
Additional Functional
#Override
public void callForNextSearchActivity() {
Intent intent = new Intent(getBaseContext(), SearchResultsActivity.class);
final GlobalClass globalVariable = (GlobalClass) getApplicationContext();
globalVariable.setSearchStr(getSearchStringFromSearchEditText());
startActivity(intent);
overridePendingTransition(R.anim.pull_in_right, R.anim.push_out_left);
}
Is it possible to have multi activity layer in Espresso testing?
If Yes .. How?
Yes, it is possible. In one of the samples they have demoed this.
https://code.google.com/p/android-test-kit/source/browse/testapp_test/src/main/java/com/google/android/apps/common/testing/ui/testapp/BasicTest.java#52][1]
public void testTypingAndPressBack() {
// Close soft keyboard after type to avoid issues on devices with soft keyboard.
onView(withId(R.id.sendtext_simple))
.perform(typeText("Have a cup of Espresso."), closeSoftKeyboard());
onView(withId(R.id.send_simple))
.perform(click());
// Clicking launches a new activity that shows the text entered above. You don't need to do
// anything special to handle the activity transitions. Espresso takes care of waiting for the
// new activity to be resumed and its view hierarchy to be laid out.
onView(withId(R.id.display_data))
.check(matches(withText(("Have a cup of Espresso."))));
// Going back to the previous activity - lets make sure our text was perserved.
pressBack();
onView(withId(R.id.sendtext_simple))
.check(matches(withText(containsString("Espresso"))));
}
Read the inline comment.
I'm trying to create a simple Android Activity test that checks that a new Activity is started when a button is clicked. The code:
public class LoginActivityTest extends ActivityInstrumentationTestCase2<LoginActivity> {
public LoginActivityTest() {
super(LoginActivity.class);
}
#Override
protected void setUp() throws Exception {
super.setUp();
setActivityInitialTouchMode(false);
mActivity = getActivity();
mLoginButton = (Button) mActivity.findViewById(R.id.login_button);
mSkipButton = (Button) mActivity.findViewById(R.id.skip_button);
}
{...}
public void testSkipButton() {
Instrumentation.ActivityMonitor monitor =
getInstrumentation().addMonitor(
"com.mycompany.myproject.view.QuestionsActivity", null, false);
mActivity.runOnUiThread(new Runnable() {
#Override
public void run() {
mSkipButton.requestFocus();
mSkipButton.performClick();
}
});
QuestionsActivity nextActivity =
(QuestionsActivity) getInstrumentation().waitForMonitorWithTimeout(monitor, 20);
assertNotNull(nextActivity);
nextActivity.finish();
}
private LoginActivity mActivity;
private Button mLoginButton;
private Button mSkipButton;
}
When I reach waitForMonitorWithTimeout() a NoClassDefFoundException is raised.
It's important to take into account that QuestionsActivity (the activity that should be launched) is a FragmentActivity, not an Activity, but FragmentActivity inherits from Activity, so I really don't understand what's happening there. Maybe InstrumentationTest cannot deal with Fragments or FragmentActivities.
mActivity is the current Activity that it's being tested, and it's a pure Activity.
Please, help!
The issue was that I added a reference to the support library from the testing project. See this link:
FragmentActivity can not be tested via ActivityInstrumentationTestCase2
Now tests work fine :)
I've got a button defined in my layout as follows :
<Button
android:id="#+id/speakButton"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:text="#string/speak"
android:onClick="speak"
/>
The onClick binds to a method in my activity, such as :
public void speak(View v)
{
// Do my stuff here
}
Using Robolectric, I'm able to create a simple test class for that activity, I'd like to know if its possible that I could have a test that invokes the button, and ensures the method in my activity was invoked OK.
(I've got a whole bunch of buttons throughout my app, so intending to have tests to ensure they are wired up correctly, unless anyone has any suggestions as to why I shoudln't bother)
#RunWith(RobolectricTestRunner.class)
public class MyActivityTest
{
private MyActivitymActivity;
private Button speakButton;
#Before
public void setUp() throws Exception
{
mActivity = new MyActivity();
mActivity.onCreate(null);
speakButton = (Button) mActivity.findViewById(com.jameselsey.apps.androidsam.R.id.speakButton);
}
#Test
public void testButtonsVisible()
{
assertThat(speakButton.getVisibility(), equalTo(View.VISIBLE));
}
#Test
public void buttonsInvokeIntendedMethods()
{
// Unsure how to implement this test
}
}
I've never used them but I believe you can do this with the TouchUtils class. Here is a link to the Android TouchUtils docs. In particular you should look at the clickView method.