'Android test'에 해당되는 글 1건

  1. 2014.12.02 AndroidStudio with Robolectric
2014.12.02 19:41

손나 유용한 링크


https://github.com/codepath/android_guides/wiki/Robolectric-Installation-for-Unit-Testing#setting-up-for-android-studio


http://zerobrain.tistory.com/42



1. 플러그인을 붙였을때 3.8 Stub 에러가 날때?

iml 파일에서 Android Platform 엔트리를 제일 하단으로 위치하기


2. 이젠 테스트 클래스를 못찾는다면?

JUnit VM option 에다가 아래와 같이 클래스 패스를 추가한다.

저 길다란 부분은 대부분 에러났을때 콘솔 로그에 찍힌 부분에서 클래스 패스를 따오면 되고, 그 뒤에다가 추가로 테스트 클래스가 들어있는 패스를 추가해야 한다.(굵은 글씨)

하지만 맨처음부터 플래이 하지말고 일단 그래들 클린, 빌드를 해줘야 한다. 그래야 테스트 클래스가 컴파일되어 .class 파일이 위치할 패스가 보이기 때문


-classpath

 "/Applications/Android Studio.app/Contents/lib/idea_rt.jar:/Applications/Android Studio.app/Contents/plugins/junit/lib/junit-rt.jar:/Users/flask/Documents/workspace_android/RobolectricTest6/build/intermediates/classes/debug:/Users/flask/Documents/workspace_android/RobolectricTest6/lib/testrunner-1.1.jar:/Users/flask/.gradle/caches/modules-2/files-2.1/org.ow2.asm/asm/5.0.1/2fd56467a018aafe6ec6a73ccba520be4a7e1565/asm-5.0.1.jar:/Users/flask/.gradle/caches/modules-2/files-2.1/org.objenesis/objenesis/1.3/dc13ae4faca6df981fc7aeb5a522d9db446d5d50/objenesis-1.3.jar:/Users/flask/.gradle/caches/modules-2/files-2.1/com.google.guava/guava/14.0.1/69e12f4c6aeac392555f1ea86fab82b5e5e31ad4/guava-14.0.1.jar:/Users/flask/.gradle/caches/modules-2/files-2.1/com.squareup.dagger/dagger/1.1.0/49f2061c938987c8e56679a731d74fd8448d8742/dagger-1.1.0.jar:/Users/flask/.gradle/caches/modules-2/files-2.1/org.hamcrest/hamcrest-library/1.1/b988c01468e3398d46678a2eb48aeb5bde271e9f/hamcrest-library-1.1.jar:/Users/flask/.gradle/caches/modules-2/files-2.1/org.apache.ant/ant/1.8.0/7b456ca6b93900f96e58cc8371f03d90a9c1c8d1/ant-1.8.0.jar:/Users/flask/.gradle/caches/modules-2/files-2.1/com.squareup/fest-android/1.0.8/72b0763d5fd11a9ca769bb88367d92e43c0198e0/fest-android-1.0.8.jar:/Users/flask/Documents/workspace_android/RobolectricTest6/lib/testrunner-runtime-1.1.jar:/Users/flask/.gradle/caches/modules-2/files-2.1/com.almworks.sqlite4java/sqlite4java/0.282/745a7e2f35fdbe6336922e0d492c979dbbfa74fb/sqlite4java-0.282.jar:/Users/flask/.gradle/caches/modules-2/files-2.1/org.apache.maven/maven-ant-tasks/2.1.3/b09be554228d66d208e5fef5266844aacf443abc/maven-ant-tasks-2.1.3.jar:/Users/flask/.gradle/caches/modules-2/files-2.1/org.robolectric/robolectric-annotations/2.4/936c649cb0958d7fb5d3c09b31c56b3997f80650/robolectric-annotations-2.4.jar:/Users/flask/.gradle/caches/modules-2/files-2.1/commons-codec/commons-codec/1.3/fd32786786e2adb664d5ecc965da47629dca14ba/commons-codec-1.3.jar:/Users/flask/Documents/workspace_android/RobolectricTest6/lib/espresso-1.1.jar:/Users/flask/.gradle/caches/modules-2/files-2.1/org.robolectric/robolectric/2.4/5b3e395f0e422de3147d42918b7a5b08476f2377/robolectric-2.4.jar:/Users/flask/Documents/android-sdk/extras/android/m2repository/com/android/support/support-v4/19.1.0/support-v4-19.1.0.jar:/Users/flask/.gradle/caches/modules-2/files-2.1/org.ow2.asm/asm-commons/5.0.1/7b7147a390a93a14d2edfdcf3f7b0e87a0939c3e/asm-commons-5.0.1.jar:/Users/flask/.gradle/caches/modules-2/files-2.1/com.ximpleware/vtd-xml/2.11/ee5bcf62c1acf76434ee9f1c67a840bafef72a6d/vtd-xml-2.11.jar:/Users/flask/.gradle/caches/modules-2/files-2.1/org.ow2.asm/asm-tree/5.0.1/1b1e6e9d869acd704056d0a4223071a511c619e6/asm-tree-5.0.1.jar:/Users/flask/.gradle/caches/modules-2/files-2.1/junit/junit/4.11/4e031bb61df09069aeb2bffb4019e7a5034a4ee0/junit-4.11.jar:/Users/flask/.gradle/caches/modules-2/files-2.1/org.hamcrest/hamcrest-core/1.1/860340562250678d1a344907ac75754e259cdb14/hamcrest-core-1.1.jar:/Users/flask/.gradle/caches/modules-2/files-2.1/org.ow2.asm/asm-analysis/5.0.1/e286fbee48efacb4e7c175f7948d9d8b2ab52352/asm-analysis-5.0.1.jar:/Users/flask/.gradle/caches/modules-2/files-2.1/org.easytesting/fest-assert-core/2.0M10/cb7c91cf614901928ae405f19d9bcdedf82781db/fest-assert-core-2.0M10.jar:/Users/flask/.gradle/caches/modules-2/files-2.1/org.easytesting/fest-util/1.2.5/c4a8d7305b23b8d043be12c979813b096df11f44/fest-util-1.2.5.jar:/Users/flask/.gradle/caches/modules-2/files-2.1/org.apache.ant/ant-launcher/1.8.0/8b53ba16fa62fb1034da8f1de200ddc407c8381/ant-launcher-1.8.0.jar:/Users/flask/.gradle/caches/modules-2/files-2.1/javax.inject/javax.inject/1/6975da39a7040257bd51d21a231b76c915872d38/javax.inject-1.jar:/Users/flask/.gradle/caches/modules-2/files-2.1/org.ow2.asm/asm-util/5.0.1/7c8caddfbd0b2d7b844f8fcc75175b9cb9cf4724/asm-util-5.0.1.jar:/Users/flask/.gradle/caches/modules-2/files-2.1/org.hamcrest/hamcrest-integration/1.1/8d47177aa4da0f259fc823a39736bad2f09993d5/hamcrest-integration-1.1.jar:/Users/flask/Documents/android-sdk/platforms/android-19/android.jar:/Users/flask/Documents/android-sdk/platforms/android-19/data/res:/Users/flask/Documents/android-sdk/tools/support/annotations.jar:/Users/flask/Documents/workspace_android/RobolectricTest6/build/test-classes"



이렇게 추가하면,


프로젝트 디렉터리 안에 app/build/test-report/debug/classes/package.name.html


에 테스트 결과가 html 로 출력됨. 



3. 그런데 robolectric 에서 api 1 을 지원하지 않는다고 하면?



@Config(manifest = "./src/main/AndroidManifest.xml", emulateSdk = 18)

@RunWith(RobolectricTestRunner.class)

public class SimpleTest {


@Test

public void testSomething() throws Exception {

Activity activity = Robolectric.buildActivity(WebViewActivity.class).create().get();

assertTrue(activity != null);

}


@Test(expected = RuntimeException.class)

public void testShouldFail(){

throw new RuntimeException();

}

}



이게 테스트 클래스인데 .@Config 에 emulateSdk = 18 를 추가해주면됨(이상하게도 19 는 안된다...?)


이렇게 하면 플래이 버튼 눌러도 테스트가 돌아감!!




build.gradle



buildscript {

    repositories {

        mavenCentral()

    }


    dependencies {

        classpath 'com.android.tools.build:gradle:0.14.4'

        classpath 'org.robolectric:robolectric-gradle-plugin:0.13.+'

    }

}


allprojects {

    repositories {

        mavenCentral()

    }

}


apply plugin: 'android'

apply plugin: 'robolectric'


android {

    packagingOptions {

        exclude 'LICENSE.txt'

        exclude 'META-INF/LICENSE'

        exclude 'META-INF/LICENSE.txt'

        exclude 'META-INF/NOTICE'

    }

    compileSdkVersion 19

    buildToolsVersion "21.1.1"


    defaultConfig {

        minSdkVersion 18

        targetSdkVersion 18

        versionCode 2

        versionName "1.0.0-SNAPSHOT"

        testInstrumentationRunner "com.google.android.apps.common.testing.testrunner.GoogleInstrumentationTestRunner"

    }

    buildTypes {

        release {

            minifyEnabled false

        }

    }


    sourceSets {

        androidTest {

            setRoot('src/test')

        }

    }

}


robolectric {

    include '**/*Test.class'

    exclude '**/espresso/**/*.class'

}


dependencies {

    repositories {

        mavenCentral()

    }

    // Espresso

    androidTestCompile files('lib/espresso-1.1.jar', 'lib/testrunner-1.1.jar', 'lib/testrunner-runtime-1.1.jar')

    androidTestCompile 'com.google.guava:guava:14.0.1'

    androidTestCompile 'com.squareup.dagger:dagger:1.1.0'

    androidTestCompile 'org.hamcrest:hamcrest-integration:1.1'

    androidTestCompile 'org.hamcrest:hamcrest-core:1.1'

    androidTestCompile 'org.hamcrest:hamcrest-library:1.1'


    androidTestCompile('junit:junit:4.11') {

        exclude module: 'hamcrest-core'

    }

    androidTestCompile('org.robolectric:robolectric:2.4') {

        exclude module: 'classworlds'

        exclude module: 'commons-logging'

        exclude module: 'httpclient'

        exclude module: 'maven-artifact'

        exclude module: 'maven-artifact-manager'

        exclude module: 'maven-error-diagnostics'

        exclude module: 'maven-model'

        exclude module: 'maven-project'

        exclude module: 'maven-settings'

        exclude module: 'plexus-container-default'

        exclude module: 'plexus-interpolation'

        exclude module: 'plexus-utils'

        exclude module: 'wagon-file'

        exclude module: 'wagon-http-lightweight'

        exclude module: 'wagon-provider-api'

    }

    androidTestCompile 'com.squareup:fest-android:1.0.+'

}


apply plugin: 'idea'


idea {

    module {

        testOutputDir = file('build/test-classes/debug')

    }

}




처음에 할때 hemcrest 디팬던시가 없으면 classnotfound가 뜨니 잘 확인하고 추가해야함.
오류들도 html로 나오는데 꼭 확인해야함!






Robolectric 테스트 작성중 문제가 몇가지 있었는데

AndroidAnnotations 의 UiThread 어노테이션이 붙은 메소드가 실행이 안되는점(웃기게도 BackgroundThread 어노테이션이 붙은 메소드는 실행이 된다...)
이때는 

public void waitForUiThread() {
try {
// Fast forward to the end of the UI queue
Thread.sleep(500); // Work around a race condition where the UI thread doesn't yet have the task in its queue
Robolectric.runUiThreadTasksIncludingDelayedTasks();
} catch (InterruptedException e) {
e.printStackTrace();
}
}

이런식으로 ui thread 를 실행하라고 명시적으로 해줘야 한다. 아오 복잡해

그리고 리스트 뷰에서 아이템 클릭은

public void performClick(ListView lv, int position) {
lv.performItemClick(lv.getChildAt(position),
position,
lv.getAdapter().getItemId(position));
}

이런식으로 해주면되고,  인텐트가 실행이 됬는지 assertion  은


public <T> void assertIntent(Activity activity, Class<? extends T> klass) {
ShadowActivity shadowActivity = shadowOf(activity);
Intent startedIntent = shadowActivity.getNextStartedActivity();
ShadowIntent shadowIntent = shadowOf(startedIntent);
assertThat(shadowIntent.getComponent().getClassName(), equalTo(klass.getName()));
}

처럼 해주면된다.

이렇게 하다보니 AA에 너무 의존된게 많아져서 activity 에서 controller 로 기능을 뽑아냈는데 @EBean 으로 인젝션 받은 Service들은 어떻게 만들기 애매했다.(rest api를 호출해서 값을 가져와야하는거라서 네트워크 딜레이라던지, 로그인을 해야하고 세션처리, 등등을 해줘야 해서 개귀찮)
그래서 Mockito를 사용해서 각각 service 들을 모두 mock 으로 만들고 외부에서 넣어줬다.

androidTestCompile 'org.mockito:mockito-core:1.+'
androidTestCompile 'com.jayway.awaitility:awaitility:1.6.3'

그런데 afterViews 에서 서비스에 접근해 값을 패치를 하는데 이때는 컨트롤러도 mock해서 해주면 된다.
하지만 컨트롤러의 기본적인 기능들은 원래의 오리지널 메소드를 호출해야 하므로 mock() 이 아닌 spy()로 만들어 주면 된다. - 그런데 doc 에선 이렇게 하는 방법이 절대 제대로 하는게 아니다. 라고 하는듯. 






저작자 표시 비영리 변경 금지
신고
Trackback 0 Comment 0


티스토리 툴바