2017-02-27 65 views
8

我想编写用于重新创建活动的测试。执行旋转是可选的。使用工具和JUnit4重新创建Android活动的测试

我希望测试能够写入最新版本的测试框架,由Google“祝福”。我是编写测试的新手,所以我想学习基本的,主流的,支持良好的工具。掌握基本知识时,任何第三方测试框架都会很好。既然我想测试非常基本的,经常发生的情况,基本的工具应该就足够了,对吧?

最少的测试代码:

public class MainActivity extends AppCompatActivity { 

    static int creationCounter = 0; 
    Integer instanceId; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 

     ++creationCounter; 
     instanceId = new Integer(creationCounter); 
     Log.d("TEST", "creating activity " + this + ", has id " + instanceId); 
    } 
} 

而且测试类:

@RunWith(AndroidJUnit4.class) 
public class ExampleInstrumentedTest { 

    @Rule 
    public ActivityTestRule<MainActivity> mActivityTestRule = new ActivityTestRule<>(MainActivity.class); 

    @Test 
    public void useAppContext() throws Exception { 

     MainActivity activity1 = mActivityTestRule.getActivity(); 
     int act1 = activity1.instanceId.intValue(); 
     int counter1 = MainActivity.creationCounter; 
     assertEquals(1, counter1); 
     assertEquals(1, act1); 


     Log.d("TEST", "requesting rotation"); 
     // method 1 
     activity1.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); 
     // method 2 //https://gist.github.com/nbarraille/03e8910dc1d415ed9740#file-orientationchangeaction-java 
     // onView(isRoot()).perform(orientationLandscape()); 

     getInstrumentation().waitForIdleSync(); // I thought this should suffice 
     // How to do this? 
     //somehowRefreshActivityInstanceInsideTestRule(); 

     MainActivity activity2 = mActivityTestRule.getActivity(); 
     int act2 = activity2.instanceId.intValue(); 
     int counter2 = MainActivity.creationCounter; 
     Log.d("TEST", "newly acquired activity " + activity2 + " has id " + act2 + "/" + counter2); 

     assertEquals(2, counter2); 
     assertEquals(2, act2); 
    } 
} 

上面的代码(无论是方法1或2)给出的logcat:如果

D/ActivityTestRule: Launching activity example.com.rotationtest.MainActivity 
D/TEST: creating activity [email protected], has id 1 
D/TEST: requesting rotation 
D/TEST: creating activity [email protected], has id 2 
D/TEST: newly acquired activity [email protected] has id 1/2 
I/TestRunner: failed: useAppContext(example.com.rotationtest.ExampleInstrumentedTest) 
I/TestRunner: ----- begin exception ----- 
I/TestRunner: java.lang.AssertionError: expected:<2> but was:<1> 

我的诊断,指正我错了:

  1. activity1.setRequestedOrientation会导致在其他线程中创建新的活动。我希望它会收到合适的包
  2. getInstrumentation()。waitForIdleSync();导致测试等到创建新活动时
  3. mActivityTestRule.getActivity();仍然返回旧的活动实例。
  4. 我需要一些方法来刷新测试规则中保存的活动实例,释放以前持有的活动实例。

我发现答案与老版本测试框架:Instrumentation test for Android - How to receive new Activity after orientation change?

mActivity.setRequestedOrientation(
    ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); 
mActivity.finish(); 
setActivity(null); 
mActivity = getActivity(); 
getInstrumentation().waitForIdleSync(); 

但我不知道如何把它转化为新的版本。

编辑:

两者在销毁状态上述假活性的方法:assertFalse(mActivityTestRule.getActivity()isDestroyed());失败。

我发现,重新创建活动实例的另一种方法(Destroy and restart Activity with Testing Support Library),而是通过不保持其状态的onSaveInstanceState

+0

ActivityTestRule.getActivity不创建一个新的活动,只是让你相同的实例 –

+0

号Yoni,我知道这是行不通的。我想知道如何使它工作,不一定使用ActivityTestRule – MateuszL

回答

0

我终于找到了在这里工作的解决方案:Get Current Activity in Espresso android

适应我的需要的代码如下所示后:

public class CurrentActivityTestRule<T extends Activity> extends ActivityTestRule<T> { 
    public CurrentActivityTestRule(Class<T> activityClass) { 
     super(activityClass, false); 
    } 

    public CurrentActivityTestRule(Class<T> activityClass, boolean initialTouchMode) { 
     super(activityClass, initialTouchMode, true); 
    } 

    public CurrentActivityTestRule(Class<T> activityClass, boolean initialTouchMode, boolean launchActivity) { 
     super(activityClass, initialTouchMode, launchActivity); 
    } 

    public T getCurrentActivity() { 
     getInstrumentation().waitForIdleSync(); 
     final Activity[] activity = new Activity[1]; 
     getInstrumentation().runOnMainSync(new Runnable() { 
      @Override 
      public void run() { 
       java.util.Collection<Activity> activities = ActivityLifecycleMonitorRegistry.getInstance().getActivitiesInStage(Stage.RESUMED); 
       activity[0] = Iterables.getOnlyElement(activities); 
      }}); 
     T current = (T) activity[0]; 
     return current; 
    } 
} 

并且用于这样的:

onView(isRoot()).perform(orientationLandscape()); 
Activity oldActivityInstance = mActivityTestRule.getActivity(); 
Activity currentActivityInstance = mActivityTestRule.getCurrentActivity(); 

我有这方面的工作与库版本:

androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 
    exclude group: 'com.android.support', module: 'support-annotations' 
}) 
androidTestCompile('com.android.support.test:runner:0.5', { 
    exclude group: 'com.android.support', module: 'support-annotations' 
})