Saturday, October 10, 2015

Robolectric 사용하기 - 1

Android Annotations Framework에 작동여부 테스트는 전부 Robolectric 2.4로 작성되어 있다. 현재는 Robolectric는 3.0 버전이 나온상태이며 내가 한번 Upgrade 해볼까 했지만 Upgrade to Robolectric 3.0에 이미 대기중이라고 Issue가 올라온 상태였다. 따라서 Robolectric에 대한 사용방법에 대한 숙지 및 추후에 Android 개발을 할때 사용하기 위해서 Robolectric에 대한 이해를 하고 넘어가기로 결정하였다. 가장 먼저 이번 포스팅에서는 Robolectric이 사용하는 방법에 대한 설명이 나와있는 Robolectric 홈페이지에 대한 번역을 진행해보았다.

Robolectric

Android Code에서 테스트 지향 개발을 하도록 도와준다.

Android emulator나 device를 이용하여 테스팅하는것은 매우 느립니다. App에 대한 Building, Deploying, Launching 과정은 1분에서 그 이상 걸리기 마련입니다. 그것을 TDD로 수행할 방법은 따로 존재하지 않습니다. 그래서 조금 더 나은 방법을 Robolectric이 제공해줍니다. IDE안 안에서 Android Test를 직접 수행해보려고 해보셨나요? 아마 시도를 해봤다면 java.lang.RuntimeException: Stub 때문에 실패를 했을 것 입니다. Robolectric은 Android SDK에서 테스트 지향 개발을 할 수 있도록 도와주는 unit test framework 입니다. Test는 JVM에서 몇초안에 수행됩니다. Robolectric 코드는 아래와 같습니다.

@RunWith(RobolectricTestRunner.class)
public class MyActivityTest {

  @Test
  public void clickingButton_shouldChangeResultsViewText() throws Exception {
    MyActivity activity = Robolectric.setupActivity(MyActivity.class);

    Button button = (Button) activity.findViewById(R.id.button);
    TextView results = (TextView) activity.findViewById(R.id.results);

    button.performClick();
    assertThat(results.getText().toString()).isEqualTo("Robolectric Rocks!");
  }
}

Robolectric은 Android SDK classes를 재사용이 가능하도록 만들어 주고 있습니다.

SDK, Resources, Native Method에 대한 Emulation이 가능합니다

Robolectric은 view, resource loading 과 같이 C에서 구현되는 native코드를 다룰 수 있습니다. 이것은 우리가 실제 디바이스에서 하는것 처럼 테스팅을 할 수 있도록 도와줍니다. 또한 이것은 분명한 SDK method를 개발하는 것을 쉽게 할 수있도록 해줍니다.

Emulator 밖에서 테스트 할 수 있습니다.

Robolectric은 emulator없이 컴퓨터에서 또는 CI JVM 환경에서 지속적인 테스트 개발이 가능합니다. 따라서 packaging, installing 과 같은작업이 필요하지 않고 몇분이 소요되는 작업에 대해서 빠르게 처리하고 리팩토링하는데 도웁을 줍니다.

Mock을 만드는 작업이 필요하지 않습니다.

Robolectric을 대체하는 다른 프로젝트 Mockito같은 것은 Android SDK에 대한 Mock작업이 필요합니다. 이것은 유효한 방법이지만, 종종 App개발에 있어 테스트 케이스가 더 많이 구현되는 상황이 발생됩니다. Robolectric은 black box testing 을 지원하기 때문에 Android 구현에 있어 Refactroing과 같은 작업에 초점을 맞출수 있도록 도와줍니다.


Get Started

Get Started

Robolectric는 Gradle 과 Maven 모두 잘 동작합니다. 프로젝트를 새로 추가하게 된다면 Gradle 빌드 방식으로 하는 것을 권장합니다. (따라서 이후에 나오는 Maven 에 대한 내용은 생략하였다. 어차피 다들 이제 Gradle쓰니까). Robolectric은 Build Tool 이 무엇이든지 사용가능합니다.

Gradle에서 Build 수행하기

가장 먼저 Robolectric을 사용하기 위해서는 build.gradle에 아래의 Dependency를 추가해야 한다.

testCompile "org.robolectric:robolectric:3.0

그리고 우리가 사용하는 테스트 상단에 아래 코드와 같이 Annotation을 작성해주면 된다.

@RunWith(RobolectricGradleTestRunner.class)
@Config(constants = BuildConfig.class)
public class SandwichTest {
}

Build system에서 생성되는 BuildConfig.class가 가지고 있는 constant field에 대해서 반드시 기술해줘야 합니다. Robolectric은 Gradle을 사용하여 프로젝트를 Build 할때 output path를 계산하기 위하여 class 안의 constant를 사용하기 때문입니다. 이 값들이 만약에 정의 되지 않았다면, Robolectric 프로젝트는 manifest, resources 또는 assets을 찾을 수가 없기 때문에 반드시 작성해주어야 합니다.

Android Studio에서 Build 수행하기

Robolectric은 Android Studio 1.1.0 과 그 이상에서 동작합니다. Gradle에서 Build를 수행하는 방법에 대해서 동일하게 작성을 해줍니다. 그리고 Build Variants Tab에 있는 Unit test support를 활성화 시킨뒤 Test 를 실행하면 됩니다.

Sample Project

Robolectric Sample 은 https://github.com/robolectric/robolectric-samples 여기서 확인 가능합니다. Gradle Starte Project는 https://github.com/robolectric/robolectric-samples여기서 확인 가능합니다.


첫번째 테스트 케이스 작성하기

가장 먼저 애플리케이션 환영 페이지 layout을 생성합니다.




    

다음 Click 버튼을 통하여 LoginActivity가 켜지는 Activity을 작성하도록 하겠습니다.

public class WelcomeActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.welcome_activity);

        final View button = findViewById(R.id.login);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                startActivity(new Intent(WelcomeActivity.this, LoginActivity.class));
            }
        });
    }
}

해당 Activity에서 테스트 할 부분은 "Login" 버튼을 클릭하였을 때 그것이 정상적인 intent로 수행되는지 여부를 판단해야 합니다. Roblectric unit testing framework를 이용하여 LoginActivity가 실제 켜지지 않아도 WelcomeActivity가 정상적으로 intent 됬는지를 아래 코드로써 확인이 가능합니다.

@RunWith(RobolectricTestRunner.class)
public class WelcomeActivityTest {

    @Test
    public void clickingLogin_shouldStartLoginActivity() {
        WelcomeActivity activity = Robolectric.setupActivity(WelcomeActivity.class);
        activity.findViewById(R.id.login).performClick();

        Intent expectedIntent = new Intent(activity, WelcomeActivity.class);
        assertThat(shadowOf(activity).getNextStartedActivity()).isEqualTo(expectedIntent);
    }
}

참고 논문 및 사이트

- Robolectric http://robolectric.org/

No comments:

Post a Comment