I'm trying to understand why concrete instances of an abstract class with android dependencies on it are unit testable. Consider the following class:
import android.arch.lifecycle.Lifecycle;
import android.arch.lifecycle.LifecycleObserver;
import android.arch.lifecycle.LiveData;
import android.arch.lifecycle.Observer;
import android.arch.lifecycle.OnLifecycleEvent;
public abstract class BaseFoo implements LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
public void onResume() {
...
}
@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
public void onCreate() {
...
}
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
public void onDestroy() {
...
}
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
public void onPause() {
...
}
...
}
And:
public class ConcreteFoo extends BaseFoo {
public void bar() {
...
}
}
The tests are based like this:
import android.arch.lifecycle.Lifecycle;
public abstract class BaseTest {
@Mock protected Lifecycle lifecycle;
...
}
Considering the android dependencies on each class, why can something like:
@RunWith(MockitoJUnitRunner.class)
public class FooTest extends BaseTest {
@Test
public void testSomething() {
...
}
}
be unit testable for ConcreteFoo
? Is it only because the lifecycle
is being mocked in BaseTest
? If so, how can it really be tested as per real devices system callbacks? How to avoid a mistake in such tests? Is there something special in Mockito that allows this that other frameworks might not have?
"Classes with Android dependencies are not testable" seems to have quite a specific meaning.
Take a classic Activity or Fragment. There is often a lot of dependency on TextView
, LayoutManager
etc. It is almost impossible to stub a behaviour on every single dependency to perform any kind of reasonable unit test. Note that the dependencies TextView
etc. are android.*
classes that are included in the runtime of a device running Android (i.e., your phone).
Poorly-designed Presenter and ViewModel classes can also have this problem. If, for instance, the Presenter or ViewModel takes a dependency on a Context it will become difficult to put inside a test harness as the android.*
Context class is difficult to mock.
However, this directive does not necessarily apply to the android.arch.*
classes. These are not included in the Android runtime on a phone and are designed in a way to facilitate testing. So in the example you have given, there doesn't seem to be a fault in including these in a class designed to be unit tested.