Как вызвать AppCompatActivity onCreate в модульном тестировании с использованием Mockito - PullRequest
0 голосов
/ 04 июля 2018

Я хочу написать простой модульный тест для класса Android Activity. Тест работает нормально, в то время как Activity расширяется, однако при расширении AppCompatActivity тест завершается неудачно:

java.lang.NullPointerException на android.support.v7.app.AppCompatDelegateImplBase. (AppCompatDelegateImplBase.java:117) на android.support.v7.app.AppCompatDelegateImplV9. (AppCompatDelegateImplV9.java:149) на android.support.v7.app.AppCompatDelegateImplV14. (AppCompatDelegateImplV14.java:56) на android.support.v7.app.AppCompatDelegate.create (AppCompatDelegate.java:202) на android.support.v7.app.AppCompatDelegate.create (AppCompatDelegate.java:183) на android.support.v7.app.AppCompatActivity.getDelegate (AppCompatActivity.java:518) на android.support.v7.app.AppCompatActivity.onCreate (AppCompatActivity.java:70) at activity.MainActivity.onCreate (MainActivity.kt: 15) at sun.reflect.NativeMethodAccessorImpl.invoke0 (собственный метод) at sun.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:43) в java.lang.reflect.Method.invoke (Method.java:498) at activity.MainActivity.onCreate (MainActivity.kt: 15)

Основной код активности:

class MainActivity : AppCompatActivity() {

    public override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        finish()
    }
}

Тестовый код с использованием Mockito:

private lateinit var mainActivitySpy: MainActivity

@Before
fun setUp() {
    mainActivitySpy = spy(MainActivity())
}

@Test
fun `Test case`() {
    mainActivitySpy.onCreate(mock())

    verify(mainActivitySpy).finish()
}

Я попытался добавить следующий код, но безрезультатно.

android {
  ...
  testOptions {
    unitTests.returnDefaultValues = true
  }
}

Есть ли способ заставить этот код работать, используя только JUnit + Mockito и никаких других сред тестирования, таких как Roboelectric и т. Д.?

Ответы [ 2 ]

0 голосов
/ 19 октября 2018

Я получил это для работы с PowerMock.

testImplementation 'org.powermock:powermock-api-mockito:1.6.6'
testImplementation 'org.powermock:powermock-module-junit4:1.6.6'

Тогда в моем тестовом классе у меня есть ...

@RunWith(PowerMockRunner.class)
@PrepareForTest({ ReportFragment.class })
public class AddEditBeaconActivityTests {

    @Test
    public void test_onCreate() {
        // Mock some data
        mockStatic(ReportFragment.class);
        MyActivity activity = spy(new MyActivity());
        doNothing().when(activity).initScreen();
        doNothing().when(activity).setContentView(R.layout.layout);
        doReturn(mock(AppCompatDelegate.class)).when(activity).getDelegate();

        // Call the method
        activity.onCreate(null);

        // Verify that it worked
        verify(activity, times(1)).setContentView(R.layout.layout);
        verify(activity, times(1)).initScreen();
    }
}

Тогда вот как выглядит MyActivity.java ...

public class MyActivity extends AppCompatActivity {

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

Это работает, потому что вы высмеиваете некоторые внутренние методы / классы, которые вызываются, когда вы вызываете super.onCreate (). Более конкретно ...

  1. Исключение NullPointerException, которое вы видите, заключается в том, что у вашего смоделированного класса нет AppCompatDelegate, и поэтому он пытается его создать. Если вы перешли в поддельный AppCompatDelegate с doReturn(mock(AppCompatDelegate.class)).when(activity).getDelegate();, вы можете обойти эту проблему.
  2. В конце концов SupportActivity попытается позвонить ReportFragment.injectIfNeededIn(this);. Простое насмешивание над этим статическим классом с помощью mockStatic (ReportFragment.class) смоделирует этот вызов. Не забудьте добавить две строки в начало вашего класса: @RunWith(PowerMockRunner.class) и @PrepareForTest({ ReportFragment.class })

Я не собираюсь спорить, следует ли вам издеваться над методом onCreate или нет. Дэвид делает очень веский аргумент. Если вам действительно нужно протестировать метод onCreate в модульных тестах, это должно сработать.

0 голосов
/ 04 июля 2018

Есть ли способ заставить этот код работать, используя только JUnit + Mockito и никаких других сред тестирования, таких как Roboelectric и т. Д.?

Нет, нет простого способа сделать это, не прибегая к фреймворку. И реальный вопрос в том, почему вы бы хотели попробовать. Тесты против Деятельности, в которых каждая отдельная зависимость подвергается моделированию, начинают вырождаться в «тестирование тавтологий», где этот тест просто отражает логику Действия без добавления какого-либо значения.

Обычная мудрость в Android состоит в том, чтобы сохранять действия, фрагменты и т. Д. Как можно более легкими, поскольку их сложно тестировать модулем. Необходимая бизнес-логика может обрабатываться тестируемым Presenter или ViewModel. Ваша книга или учебник должны охватывать это.

Если вам необходимо написать тест для Активности, вы можете написать Инструментированный модульный тест, в котором на устройстве создается реальная Активность. См. официальную документацию о том, как это сделать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...