May 2, 2012

Android: Robotium을 이용한 Twitter 테스팅

Robotium은 Android SDK가 제공하는 테스팅 프레임워크를 더 편하게 사용할 수 있도록 해준다. Robotium을 사용하여 개발중인 프로그램의 테스트도 가능하지만 다른 개발자의 프로그램도 자동화 테스트가 가능하다. (예를 들어, Twitter 프로그램이 네트워크에 미치는 영향을 평가해보기 위해 자동화를 할 필요가 있을 수 있다)

이 글에서는 Twitter Android 클라이언트를 Robotium을 사용하여 실행하고 간단한 사용자 동작을 자동화하는 방법에 대해 살펴보겠다.

1. Twitter Client API 파일 다운 받기

http://www.apkdot.com/download.php?url=http://www.apkdot.com/apk/Twitter_3.1.1.apk

2. APK 파일을 debug certificate으로 사인하기

테스트하려는 대상과 테스트 프로그램이 서로 다른 certificate으로 사인되어있으면 테스트 수행이 불가하다. 이를 해결하기 위해 Twitter APK 파일을 내가 가진 certificate으로 다시 사인해주어야한다.

  • APK 파일의 압축을 푼다. ZIP 포맷이므로 확장자를 ZIP으로 바꾸고 압축을 푼다.
  • META-INF 폴더를 삭제한다.
  • 다시 ZIP으로 압축한 후 APK 확장자로 변경한다.
  • jarsigner로 APK 파일을 signing한다.
    • jarsigner -keystore ~/.android/debug.keystore -storepass android -keypass android twitter-3.1.1.apk androiddebugkey
  • zipalign을 실행한다.
    •  zipalign 4 twitter-3.1.1.apk twitter-3.1.1-aligned.apk
  • 최종 생성된 twitter-3.1.1-aligned.apk를 사용할 것이다.


3. APK 파일 설치

Android 에뮬레이터에 APK 파일을 설치한다. Emulator를 실행하기 위해 emulator -avd <device name> 명령을 터미널에서 수행한다. Emulator 실행 전에 해당 device를 AVD Manager에서 미리 만들어 놓아야한다. 

adb install <path>/twitter-3.1.1.apk

위 명령을 실행하여 APK를 설치할 수 있다.

4. APK 파일의 정보 얻기

테스트 프로그램 실행에 필요한 Twitter 프로그램의 정보를 얻어야한다. 패키지 이름과 Activity 이름을 얻기 위해 아래와 같은 명령을 실행한다.

aapt dump badging <path>/twitter-3.1.1.apk

패키지 이름은 "com.twitter.android" 이고 launchable-activity: name='com.twitter.android.StartActivity' 항목을 보면 실행 가능한 Activity는 com.twitter.android.StartActivity이다.

5. Robotium 테스트 프로그램 작성하기

 Eclipse에서 Android Test Project로 새 프로젝트를 만든다. 새 프로그램의 Java Package 이름은 반드시 com.twitter.android.test로 지정한다. AndroidManifest.xml 파일이 아래와 같이 package name과 target package를 수정한다.


<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.twitter.android.test"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk android:minSdkVersion="10" />

    <instrumentation
        android:name="android.test.InstrumentationTestRunner"
        android:targetPackage="com.twitter.android" />

    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name" >
        <uses-library android:name="android.test.runner" />
    </application>
</manifest>

아래와 같이 main 소스 코드를 작성한다. 이 코드를 실행하기 위해서는  Run As에서 Android Junit Test로 실행해주어야 한다. 정상적으로 실행된다면 Twitter가 실행된 후 계정을 만드는 화면으로 자동적으로 전환될 것이다. Good Luck!

====

package com.twitter.android.test;

import android.test.ActivityInstrumentationTestCase2;
import android.app.Instrumentation;
import android.view.MotionEvent;
import android.util.Log;
import android.app.Activity;
import com.jayway.android.robotium.solo.Solo;
import java.lang.Runnable;
import java.lang.Thread;

@SuppressWarnings("unchecked")
public class TestApk extends ActivityInstrumentationTestCase2 {
    private static final String TARGET_PACKAGE_ID = "com.twitter.android";
    private static final String LAUNCHER_ACTIVITY_FULL_CLASSNAME = "com.twitter.android.StartActivity";
    private static Class launcherActivityClass;
    
    static {
        try {
            launcherActivityClass = Class.forName(LAUNCHER_ACTIVITY_FULL_CLASSNAME);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
    }
    
    public TestApk() throws ClassNotFoundException {
        super(TARGET_PACKAGE_ID,launcherActivityClass);
        Log.i("TestApk", "Constructor");
    }
    
    private Solo solo;
    private Instrumentation inst;
    private Activity activity;
    
    @Override
    public void setUp() throws Exception {
        super.setUp();
        solo = new Solo(this.getInstrumentation());
        
        // 실행 시 Hang 이슈를 해결하기 위해 Thread를 사용하였다.
        final Runnable r = new Runnable() 
        {
            public void run()
            {
                TestApk.this.getActivity();
            }
        };
        
        Thread t = new Thread(r);
        t.start();
    }
    
    @Override
    public void tearDown() throws Exception {
        Log.i("TestApk", "tearDown");
    }
    
    public void testLogin() throws InterruptedException {
        Log.i("TestApk", "testLogin");
        solo.sleep(15000);
        solo.clickOnScreen(100, 750);
        Log.i("TestApk", "clicked");
        solo.sleep(5000);
    }
}


No comments:

Post a Comment