in package Android

Andorid Studio, Gradle 테스트 셋팅하기

4주 전쯤 서울에서 Vingle과 함께 하는 ‘가을밤의 코딩이야기’에 다녀왔습니다. 행사의 주제는 현재 Vingle에서는 어떻게 프로젝트를 진행하고 있는지에 대해 알려주는 자리였습니다.

TDD & Agile in Vingle

50명 정도를 초대하는 자리였지만 200명 이상이 지원했다고 합니다. 행사 이후에 실제로 어떻게 개발하는지 웹, 안드로이드, 아이폰으로 세션을 나누어 Vingle 개발자들분들이 직접 TDD로 개발하는 방법을 알려주는 자리를 가졌습니다. 그래서 이번에 배워온 것들을 기반으로 Android Studio 설치도 해보고 TDD 개발을 위한 셋팅을 일주일 가량 걸려서 해보았습니다.

Android Studio 에서는 기본으로 프로젝트를 생성하거나 기존의 프로젝트를 가져올 때 Gradle로 가져옵니다. 전 기존의 프로젝트를 가져오는 것을 목표로 셋팅을 했구요. 그래도 기본 부터 알아야 셋팅을 할 수 있을 거라 생각해서 Robolectric, Gradle 설정 부터 시작했습니다.

Gradle은 기본적으로 build.gradle 이라는 파일에서 라이브러리 설정이나 프로젝트 관계 설정과 같은 전체적인 프로젝트 설정을 담당하고 있습니다. 사실 Maven으로 설정을 시작해보려다가 요즘엔 Maven에서 Gradle로 넘어오는 추세라고 해서 그냥 일일이 찾아가며 설정을 했구요. 시작해보도록 하겠습니다.

buildscript {
    repositories {
        mavenCentral()
    }

    dependencies {
        classpath 'com.android.tools.build:gradle:0.6.+'
        // 추가할 부분
        classpath 'com.github.jcandksolutions.gradle:android-unit-test:1.0.+'

    }
}
apply plugin: 'android'

repositories {
    mavenCentral()
}

android {
    compileSdkVersion 17
    buildToolsVersion "17.0.0"

    defaultConfig {
        minSdkVersion 10
        targetSdkVersion 17
        // 추가할 부분
        packageName "com.kevin.tddtest"
    }
}

apply plugin: 'android-unit-test'

dependencies {
    repositories {
        mavenCentral()
    }

    compile 'com.android.support:support-v4:18.0.0'
    compile 'com.android.support:appcompat-v7:+'

    // 추가할 부분
    // test 관련
    testCompile 'junit:junit:4.10'
    testCompile 'org.robolectric:robolectric:2.1.+'
    testCompile 'com.squareup:fest-android:1.0.+'
}

그리고 여기에서 Robolectric 을 왜 사용하는가 하면 Android에서 기본적으로 제공해주는 UnitTest Framework는 실행시 시간이 오래 걸리는 단점이 있기 때문에 이를 보완한 Robolectric을 사용합니다. packageName 또한 잊지 말고 프로젝트 생성할 때 넣어준 프로젝트 패키지 이름을 적어주면 됩니다. 또한 build.gradle 파일은 컴파일 할 때 순서를 의미하기 때문에 정확하게 입력해야 오류를 최소화 시킬 수 있어요. 특히 apply plugin: ‘android-unit-test’를 꼭 추가하셔야 합니다.

이렇게 셋팅을 하고 나면 설정한 라이브러리를 가져오기 위해서 상단 메뉴에 위치한 Sync 버튼을 눌러서 작성한 스크립트가 적용될 수 있도록 합니다. 그러면 왼쪽 프로젝트 하단에 있는 External Libraries에 많은 라이브러리들이 자동으로 추가가 될거에요.

그리고 테스트 패키지를 만들기 위해서 다음과 같은 구조가 되도록 패키지를 만들어야 합니다.

Project Root

+  My Application

  +– src

  |   +– main

  |   |   +– java

  |   |   +– res  

  |   |   \– AndroidManifest.xml

  |   ㅏ— test    

  |   |   +— java      <-------------- Mark Directory As 에서 Test Source Root로 바꿔줍니다

  +– build.gradle

|– build.gradle

ㄴ–settings.gradle

이해가 되지 않으신다면 main가 같은 폴더 안에 test 폴더를 만드시구요. test 폴더 안에 다시 java폴더를 만드시면 됩니다. My Application에 있는 build.gradle은 비워두시면 됩니다. 이렇게 기본 설정을 마쳤는데 아직 많은 내용이 빠진 것 같아서 여러번의 수정이 필요할 것 같습니다. 저도 LittleInnov 님이 올려 놓으신 블로그를 참고해서 설정을 했거든요. 많은 도움 주셔서 감사합니다.

LittleInnov 님 블로드 주소 : http://valley.egloos.com/viewer/?url=http://deepseadk.egloos.com/1795460

JUnit Test Code

import org.junit.Before;
import org.junit.Test;

import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;

/**
 * Created by kevin on 2013. 11. 8..
 */

// jUnit Test
public class RobolTest {
    int a;
    int b;

    @Before
    public void setUp() {

    }

    @Test
    public void testRobolTest2() {
        assertThat(1, is(1));
    }

    @Test
    public void testRobolTest1() {
         assertThat(1, is(1));
    }
}

Robolectric Test Code

package com.kevin.tddtest;

import org.junit.runners.model.InitializationError;
import org.robolectric.AndroidManifest;
import org.robolectric.AndroidManifestExt;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import org.robolectric.res.Fs;

/**
 * Created by kevin on 2013. 11. 8..
 */
public class RobolectricGradleTestRunner extends RobolectricTestRunner {
    public RobolectricGradleTestRunner(final Class<!--?--> testClass) throws InitializationError {
        super(testClass);
    }

    @Override
    protected AndroidManifest getAppManifest(final Config config) {
        final String manifestProperty = System.getProperty("android.manifest");
        if (config.manifest().equals(Config.DEFAULT) && manifestProperty != null) {
            final String resProperty        = System.getProperty("android.resources");
            final String assetsProperty     = System.getProperty("android.assets");
            final String packageProperty    = System.getProperty("android.package");

            final AndroidManifestExt a  = new AndroidManifestExt(Fs.fileFromPath(manifestProperty), Fs.fileFromPath(resProperty), Fs.fileFromPath(assetsProperty));
            a.setPackageName(packageProperty);
            return a;
        }
        return super.getAppManifest(config);
    }
}

org.robolectric 패키지 생성 후 AndroidManifestExt 생성

package org.robolectric;

import org.robolectric.res.FsFile;

/**
 * Created by kevin on 2013. 11. 8..
 */

public class AndroidManifestExt extends AndroidManifest {
    private static final String R = ".R";
    private String mPackageName;
    private boolean isPackageSet;

    public AndroidManifestExt(final FsFile androidManifestFile, final FsFile resDirectory, final FsFile assetsDirectory) {
        super(androidManifestFile, resDirectory, assetsDirectory);
    }

    @Override
    public String getRClassName() throws Exception {
        if (isPackageSet) {
            parseAndroidManifest();
            return mPackageName + R;
        }
        return super.getRClassName();
    }

    @Override
    public String getPackageName() {
        if (isPackageSet) {
            parseAndroidManifest();
            return mPackageName;
        } else {
            return super.getPackageName();
        }
    }

    public void setPackageName(final String packageName) {
        mPackageName = packageName;
        isPackageSet = packageName != null;
    }
}

Comments

comments

댓글 남기기

This site uses Akismet to reduce spam. Learn how your comment data is processed.