Android JUnit Tests Hang when run together

I apologize in advance for posting a lot of code, this problem really got me!

I have two Android JUnit tests that are causing me problems. Run each one separately and they work fine, but when run together (PasswordEntryActivityTests and then CryptoKeystoreTests) CryptoKeystoreTests hangs indefinitely.

I know that not only is the emulator slow because each one individually finishes in less than a second, but it can hang for more than 20 minutes. I also tested it on a real device (Droid Razr) and it does the same thing.

The problematic code is PasswordEntryActivity.launchNewPasswordActivity()

. Removing this feature makes everything work fine.

Suspending a function in the debugger while it is hanging says this:

MessageQueue.nativePollOnce(int, int) line: not available [native method]

      

What's happening?

I copied below:

  • PasswordEntryActivity
  • PasswordEntryActivityTests
  • CryptoManagerKeystoreTests

Please let me know to post any other code you would like to see. Thank!

    public class PasswordEntryActivity extends Activity 
    {
...
        private void launchNewPasswordActivity()
        {
            Intent launchNewPasswordIntent = new Intent(this, NewPasswordActivity.class);
            startActivity(launchNewPasswordIntent);
        }

        @Override
        protected void onCreate(Bundle savedInstanceState) 
        {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.password_entry_layout);
...
            //this code should be LAST in onCreate because it exits the Activity
            //CryptoManager.passwordIsRight returns 0 if no password has been set
            passwordExists = CryptoManager.passwordIsRight("x", this) != 0;
            if(!passwordExists)
                launchNewPasswordActivity();
        }
    }

      

This activity test:

    //supposed to make sure the application responds correctly when no password is set
    public class PasswordEntryActivityTests extends android.test.ActivityInstrumentationTestCase2<                          crypnote.controller.main.PasswordEntryActivity>{
    protected void setUp() throws Exception 
    {
        passwordEntryActivity = getActivity();

        //delete the database if it exists
        File file = passwordEntryActivity.getFileStreamPath(DBInterface.Constants.DatabaseName);
        if(file.exists())
            assertTrue(file.delete());
        file = passwordEntryActivity.getFileStreamPath(CryptoManager.Constants.KEYSTORE_PATH);
        if(file.exists())
            assertTrue(file.delete());
    }
    //allows us to access the interface
    @UiThreadTest
    public void testNoPassword() throws Exception
    {
        passwordEntryActivity  = getActivity();

        EditText passwordEntryEditText = 
                (EditText) passwordEntryActivity.findViewById(
                crypnote.controller.main.R.id.passwordentrylayout_passwordedittext);
        Button unlockButton = (Button) passwordEntryActivity.findViewById(
                                        crypnote.controller.main.R.id.passwordentrylayout_unlockbutton);


        int passwordResult = CryptoManager.passwordIsRight("x", getActivity());
        assertTrue(passwordResult == 0);

        //pass a wrong password to the edittext and click the unlock button
        passwordEntryEditText.setText("x");
        assertTrue(unlockButton.performClick());

        //get the foreground activity class name
        ActivityManager am = (ActivityManager) passwordEntryActivity.
                                                        getSystemService(Context.ACTIVITY_SERVICE);

        // get the info from the currently running task
        List< ActivityManager.RunningTaskInfo > taskInfo = am.getRunningTasks(1); 

        ComponentName componentInfo = taskInfo.get(0).topActivity;
        String foregroundClassName = componentInfo.getShortClassName();

        //don't forget the leading '.'
        assertTrue(!foregroundClassName.equals(".PasswordEntryActivity"));
    }
}

      

CryptoKeystoreTests:

public class CryptoKeystoreTests extends android.test.ActivityInstrumentationTestCase2<
                                                                crypnote.controller.main.PasswordEntryActivity>
{
    public void testKeystore() throws Exception
    {
        Context context = getActivity();

        //delete the database if it exists
        File file = context.getFileStreamPath(DBInterface.Constants.DatabaseName);
        if(file.exists())
            assertTrue(file.delete());
        file = context.getFileStreamPath(CryptoManager.Constants.KEYSTORE_PATH);
        if(file.exists())
            assertTrue(file.delete());

        CryptoManager cryptoManager=null;
        String password = CryptoManager.Constants.DEBUG_PASSWORD;
        FileInputStream fis=null;

            //the cryptomanager will generate a new key and keystore
            cryptoManager = new CryptoManager(password, context);
            Key CRYPTOKEY = cryptoManager.getKey();
            cryptoManager.close();

            //initialize KeyStore
            KeyStore keystore = KeyStore.getInstance(Constants.KEYSTORE_INSTANCE_TYPE);
            fis = context.openFileInput(CryptoManager.Constants.KEYSTORE_PATH);
            keystore.load(fis, password.toCharArray());

            assertTrue(keystore.containsAlias(Constants.APP_ALIAS));    
            assertTrue(keystore.isKeyEntry(Constants.APP_ALIAS));

            Key key = keystore.getKey(CryptoManager.Constants.APP_ALIAS, 
                                        password.toCharArray());
            assertTrue(key.getAlgorithm().equals(CryptoManager.Constants.PROVIDER_NAME));

            assertTrue(key.getAlgorithm().equals(CRYPTOKEY.getAlgorithm()));
            assertTrue(key.getFormat().equals(CRYPTOKEY.getFormat()));

            if(fis != null)
                fis.close();
    }
}

      

EDIT: NewPasswordActivity.onCreate:

@Override
protected void onCreate(Bundle savedInstanceState) 
{
    super.onCreate(savedInstanceState);
    setContentView(R.layout.new_password_layout);
}

      

+3


source to share


1 answer


It hangs because PasswordEntryActivityTests doesn't fire / end resource / UI events that were addressed / created by itself during its own lifecycle, or rather, then reopened NewPasswordActivity.

PasswordEntryActivityTests begins by testing the creation of the PasswordEntryActivity i.e. getActivity()

that as a result, based on the start condition of the second NewPasswordActivity, the newly opened NewPasswordActivity takes up the foreground window and remains forever, the developer must release it correctly after you have checked your testing.



In benchmark test, the correct way to detect / monitor the launch of the second activity from the current activity is to use ActivityMonitor , see pseudo code below:

// No password result starting a second activity.
public void testNoPassword() {
  // register NewPasswordActivity that need to be monitored.
  ActivityMonitor activityMonitor = getInstrumentation().addMonitor(NewPasswordActivity.class.getName(), null, false);

  // Get current activity, it will start NewPasswordActivity in consequence.
  PasswordEntryActivity currentActivity = getActivity();

  NewPasswordActivity nextActivity = getInstrumentation().waitForMonitorWithTimeout(activityMonitor, 5);
  // NewPasswordActivity is opened and captured.
  assertNotNull(nextActivity);
  // Don't forget to release/finish NewPasswordActivity after test finish.
  nextActivity.finish();
}

      

+2


source







All Articles