3

たくさんのコードを投稿してしまったことを前もってお詫びします。この問題は本当に私を襲いました!

問題を引き起こしているAndroidJUnitテストが2つあります。それぞれを個別に実行すると正常に機能しますが、一度に実行すると(PasswordEntryActivityTests、次にCryptoKeystoreTests)、CryptoKeystoreTestsが無期限にハングします。

それぞれが1秒未満で個別に終了するため、エミュレータが遅いだけでなく、20分以上ハングする可能性があることを私は知っています。また、実際のデバイス(Droid Razr)でテストしましたが、同じことを行います。

問題のあるコードはPasswordEntryActivity.launchNewPasswordActivity()です。その機能を削除すると、すべてが正常に機能します。

ハングしているときにデバッガーで関数を一時停止すると、次のようになります。

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

どうしたの?

以下にコピーしました:

  • PasswordEntryActivity
  • PasswordEntryActivityTests
  • CryptoManagerKeystoreTests

あなたが見たい他のコードを投稿することを私に知らせてください。ありがとう!

    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();
        }
    }

そのアクティビティのテスト:

    //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();
    }
}

編集:NewPasswordActivity.onCreate:

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

1 に答える 1

2

PasswordEntryActivityTestsは、自身の実行ライフサイクル、より具体的には、新しく開かれたNewPasswordActivityの間に、それ自体でアドレス指定/作成されたリソース/ UIイベントを解放/終了しないため、ハングします。

PasswordEntryActivityTestsは、PasswordEntryActivityの作成をテストすることから始まります。つまりgetActivity()、条件に基づいて、2番目のNewPasswordActivityを起動します。新しく開かれたNewPasswordActivityはフォアグラウンドウィンドウを占有し、永久に残ります。テスト。

インストルメンテーションテストでは、現在のアクティビティから2番目のアクティビティの起動を検出/監視する正しい方法はActivityMonitorを使用することです。以下の擬似コードを参照してください。

// 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();
}
于 2013-02-02T12:00:20.517 に答える