Robolectric 은 실제 Android framework code 를 포함한 런타임 환경을 생성하여 동작합니다.
그렇기에 테스트할 때 실제 기기에서 테스트 하는 것과 같은 테스트가 가능합니다.
Robolectric 은 다음과 같은 한계점을 갖고 있습니다.
- Native code - Android Native Code 는 Robolectric 환경에서 실행할 수 없습니다.
- Out of process calls - Robolectric 환경에는 Android System service 가 없습니다.
- Inadequate testing APIs - Android 는 테스팅에 적합한 API 를 갖고 있지 않습니다.
Robolectric 은 이러한 문제를 해결하기 위해 Shadows 를 제공합니다.
Shadow 는 Android 클래스들의 동작을 확장하고 변경할 수 있습니다. 안드로이드 클래스가 초기화되면, Robolectric 은 대응되는 shadow class 를 찾습니다. 그리고 그에 맞는 Shadow 객체를 생성하여 연결합니다.
Robolectric 은 바이트 코드를 사용하여 Native code 를 대체하는 Fake implementation 을 구현하고, 추가적으로 테스트 할 수 있는 API 를 제공합니다.
Shadow Classes
Shadow 클래스는 인자 값이 없는 생성자를 필요로 합니다.
그래야 Robolectric 이 인스턴스를 생성할 수 있습니다. 그리고 그 클래스에 @Implements 어노테이션과 함께 안드로이드의 어떤 클래스를 Shadow 하는 것인지 명시하여 적용해줍니다.
예시는 다음과 같습니다.
// TextView에 대한 Shadow 클래스
@Implements(TextView.class)
public class ShadowTextView extends ShadowView {
// 다음과 같이 선언을 해주던가, 아니면 선언을 하지 않는다.
// (컴파일러가 기본 생성자를 자동으로 생성하기 때문)
public ShadowTextView() {
super();
}
}
Shadow Methods
Shadow 메소드는 안드로이드 클래스에서 정의된 메소드와 똑같은 시그니쳐로 선언하고 @Implementation
어노테이션을 적용하여 구현하면 됩니다.
그러면 Robolectric 이 알아서 그 메소드를 호출해줍니다.
예를 들어 안드로이드의 ImageView#setImageResource(int resId)
라는 메소드를 Shadowing 해보겠습니다.
@Implements(ImageView.class)
public class ShadowImageView extends ShadowView {
@Implementation
protected void setImageResource(int resId) {
// implementation here.
}
}
이때 Shadowing 의 대상이 되는 메소드는 private
, static
, final
등 모두 상관 없이 적용 가능합니다.
@Implementation
이 붙은 Shadowing 메소드는 일반적으로 protected
으로 지정해줍니다.
한 가지 유의 할 점은 Shadowing 의 대상이 되는 메소드는 Shadow 클래스의 대상이 되는 오리지널 클래스에서 정의된 메소드여야 한다는 것입니다. 예를 들어 View 클래스에서 정의된 setEnabled() 메소드는 ViewGroup 클래스를 Shadow 한 클래스에서 Shadow method 로 사용할 수 없습니다.
Shadow constructors
생성자도 Shadow 할 수 있습니다.
이때는 메소드와 똑같이 @Implementation 을 붙여주고, 생성자의 이름은 __constructor__
으로 선언합니다. 단, 이때도 역시나 Shadowing 하고자 하는 오리지널 생성자와 파라미터를 똑같이 구성해야 합니다.
예를 들어 TextView 의 생성자를 Shadow 하는 코드는 아래와 같습니다.
@Implements(TextView.class)
public class ShadowTextView extends ShadowView {
private Context context;
@Implementation
protected void __constructor__(Context context) {
this.context = context;
}
}
Using a Custom Shadows
이제 Shadow를 만들었으니 사용도 해보겠습니다. Custom Shadow 클래스들은 @Config 어노테이션의 shadows 필드로 지정해야 사용할 수 있습니다.
예를 들어 위에서 만든 ShadowTextView 를 사용하기 위해서는 @Config(shadows={ShadowTextView.class}) 라고 선언해주어야 합니다. 보시다시피 array 로 값을 받기 때문에 1개 이상의 Shadow 클래스를 적용할 수 있습니다.
만약 하나의 클래스나 메소드가 아닌 패키지 단위로 적용하고 싶다면 robolectric.properties
에 선언하면 됩니다.
커스텀 Shadow 클래스를 코드상에서 사용할 때는 Shadows.shadowOf()
메소드가 아닌 Shadow.extract()
메소드를 통해 리턴 받은 값을 적절하게 캐스팅하여 사용해야 합니다.
'Android > Test' 카테고리의 다른 글
[Android Test] 4) Robolectric 테스트 환경 설정하기(Configuration) (0) | 2020.03.14 |
---|---|
[Android Test] 3) Robolectric API 와 AndroidX Test API 잘 알고 쓰기 (2) | 2020.03.13 |
[Android Test] 2) Robolectric 설치 및 환경 설정 (0) | 2020.03.12 |
[Android Test] 1) Robolectric 이란? (0) | 2020.03.11 |
[Android UI Test] 6) Espresso 를 활용한 WebView Test (0) | 2020.03.10 |