android - 测试 Activity 是否返回预期结果

标签 android testing junit android-activity instrumentation

我有以下 Activity :

package codeguru.startactivityforresult;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class ChildActivity extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.child);

        this.resultButton = (Button) this.findViewById(R.id.result_button);
        this.resultButton.setOnClickListener(onResult);
    }

    private View.OnClickListener onResult = new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            Intent result = new Intent();
            result.putExtra(ChildActivity.this.getString(R.string.result), ChildActivity.this.getResources().getInteger(R.integer.result));
            ChildActivity.this.setResult(RESULT_OK, result);
            ChildActivity.this.finish();
        }
    };
    private Button resultButton = null;
}

以及以下 JUnit 测试:

package codeguru.startactivityforresult;

import android.app.Activity;
import android.test.ActivityInstrumentationTestCase2;
import android.test.UiThreadTest;
import android.widget.Button;
import junit.framework.Assert;

public class ChildActivityTest extends ActivityInstrumentationTestCase2<ChildActivity> {

    public ChildActivityTest() {
        super(ChildActivity.class);
    }

    @Override
    public void setUp() throws Exception {
        super.setUp();

        this.setActivityInitialTouchMode(false);

        this.activity = this.getActivity();
        this.resultButton = (Button) this.activity.findViewById(R.id.result_button);
    }

    @Override
    public void tearDown() throws Exception {
        super.tearDown();
    }

    @UiThreadTest
    public void testResultButtonOnClick() {
        Assert.assertTrue(this.resultButton.performClick());
        Assert.fail("How do I check the returned result?");
    }
    private Activity activity;
    private Button resultButton;
}

我如何确保单击按钮设置正确的结果(通过调用 setResult()),该结果将返回到使用 startActivityForResult() 启动此 Activity 的任何 Activity ?

最佳答案

对于问题中的当前 Activity 实现,即通过单击 ChildActivity 中的按钮设置结果然后立即销毁 Activity,我们在 ChildActivityTest 中可以做的测试结果相关的东西不多。

相关问题的答案Testing onActivityResult()展示了如何在 MainActivityTest 中独立地对 startActivityForResult() 和/或 onActivityResult() 进行单元测试。通过独立方式 MainActivityTest 不依赖于 ChildActivity 的交互,检测将捕获 ChildActivity 创建并立即终止它,然后返回一个准备好的烘焙模拟 ActivityResult,因此单元测试 MainActivity。

如果您不希望检测中断并返回模拟的 ActivityResult,您可以让 ChildActivity 继续运行,然后模拟 ChildActivity 中的交互,并将真实的 ActivityResult 返回给 MainActivity。说如果您 MainActivity 为结果启动 ChildActivity 然后更新一个 TextView,以测试整个端到端的交互/合作,请参见下面的示例代码:

public class MainActivityTest extends ActivityInstrumentationTestCase2<MainActivity> {
  ... ...

  public void testStartActivityForResult() {
    MainActivity mainActivity = getActivity();
    assertNotNull(activity);

    // Check initial value in TextView:
    TextView text = (TextView) mainActivity.findViewById(com.example.R.id.textview1);
    assertEquals(text.getText(), "default vaule");

    try {
      Thread.sleep(2000);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }

    // Create an ActivityMonitor that monitor ChildActivity, do not interrupt, do not return mock result:
    Instrumentation.ActivityMonitor activityMonitor = getInstrumentation().addMonitor(ChildActivity.class.getName(), null , false);

    // Simulate a button click in MainActivity that start ChildActivity for result:
    final Button button = (Button) mainActivity.findViewById(com.example.R.id.button1);
    mainActivity.runOnUiThread(new Runnable() {
      public void run() {
        button.performClick();
      }
    });

    try {
      Thread.sleep(2000);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }

    getInstrumentation().waitForIdleSync();
    ChildActivity childActivity = (ChildActivity) getInstrumentation().waitForMonitorWithTimeout(activityMonitor, 5);
    // ChildActivity is created and gain focus on screen:
    assertNotNull(childActivity);

    // Simulate a button click in ChildActivity that set result and finish ChildActivity:
    final Button button2 = (Button) childActivity.findViewById(com.example.R.id.button1);
    childActivity.runOnUiThread(new Runnable() {
      public void run() {
        button2.performClick();
      }
    });

    try {
      Thread.sleep(2000);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }

    getInstrumentation().waitForIdleSync();
    // TextView in MainActivity should be changed:
    assertEquals(text.getText(), "default value changed");
  }

  ... ...
}

我在这里添加了三个 Thread.sleep() 调用,这样您就可以在运行 JUnit 测试时看到按钮单击模拟。正如您在这里看到的,独立的 ChildActivityTest 不足以测试整个协作,我们实际上是通过 MainActivityTest 间接测试 ChildActivity.setResult(),因为我们需要从一开始就模拟整个交互。

关于android - 测试 Activity 是否返回预期结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13041890/

相关文章:

java - 如何使用泛型类型模拟 ResponseEntity<?> ?

android - Horizo​​ntalScrollView 内的 RecyclerView 不显示所有项目

android - 如何使用 lint.xml 从 Android Studio 中的 lint 中排除一些未使用的图像?

android - pressBack() 在 Espresso 测试中被忽略

java - 使用 Mockito 调用最终类静态方法的模拟对象

java - Spring JUnit 测试中未调用 Hibernate 监听器

java - 使用特定大小时如何使单行EditText正确绘制自身

android - Unity Android APK 在启动时崩溃

c# - 测试工具与测试框架有何不同/

xml - 使用 JUnit 样式的 xml 输出的 Lua 自动化测试?