У меня есть активность
public class MyActivity extends ActionBarActivity { public int i; @Override protected void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); i = getSomeInt(); } protected int getSomeInt() { return 1; // here can be an api-request } }
И я хочу протестировать его с robolectric 3.0
и mockito
.
Но мне нужно getSomeInt()
.
@RunWith(RobolectricGradleTestRunner.class) @Config(constants = BuildConfig.class) public class MyActivityTest { private MyActivity mActivity; @Before public void setUp() { mActivity = spy(Robolectric.buildActivity(MyActivity.class).create().get()); doReturn(2).when(mActivity).getSomeInt(); //but it is already after onCreate! } @Test public void testGetInt() { assertEquals(2, mActivity.i); //error } }
Можно ли использовать уже издевавшийся метод путем создания активности?
РЕДАКТИРОВАТЬ
я пытался
@Before public void setUp() { ActivityController<MyActivity> co = Robolectric.buildActivity(MyActivity.class); mActivity = spy(co.get()); doReturn(2).when(mActivity).getSomeInt(); co.create(); }
Но мне кажется, что onCreate
не вызывался mActivity
assertEquals(2, mActivity.i);
// дает результат:
java.lang.AssertionError: Expected :2 Actual :0
Спасибо Eugen за внимание, он не работает, потому что create
вызов на контроллере, который работает с активностью, которая не отслеживается
Мокито только издевается над объектом. Но он не может изменить ссылку на ActivityController
.
Поэтому я пытаюсь изолировать функцию и передать ее активности перед созданием.
Четыре этапа:
Изолировать функции как член нового класса
public class SomeInt{ public int get() { return 1; // here can be an api-request } }
Использовать функции объектом в MyActivity
public class MyActivity extends ActionBarActivity { SomeInt someInt; @Override protected void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); i = someInt.get(); } }
Сделать API для установки объекта someInt
в тесте
Используйте ShadowActivity
– я рекомендовал это, разделив код и тест
@Implements(MyActivity.class) public class ShadowMyActivity extends ShadowActivity { @RealObject private MyActivity myActivity; @Implementation public void setForMockito(SomeInt someint) { myActivity.someint = someint; } }
Или позволить публичному объекту
public SomeInt someInt;
Или сделать публичный сеттер для объекта в MyActivity
Макет в тесте
Если используется ShadowActivity
@Config(constants = BuildConfig.class shadows = ShadowMyActivity.class) Class TestMyActivity { @Before public void setUp() { SomeInt someIntMock = mock(SomeInt.class); ActivityController<MyActivity> co = Robolectric.buildActivity(MyActivity.class); mActivity.setForMockito(someIntMock); doReturn(2).when(someIntMock).get(); co.create(); // verify here or in tearDown } ... }
Я не думаю, что это возможно. Я попытался создать Activity в тесте, шпионить его, а затем создать контроллер с этим шпионом, и я не мог заставить его работать, поэтому я не могу представить, как вы могли это сделать.
Теперь, когда сказано, это не означает, что нет решения вашей основной проблемы, просто слепое действие не способ сделать это. Я бы посоветовал вам задать второй вопрос, в котором вы конкретно объясняете, чего вы пытаетесь достичь (например, издеваетесь над сетевым компонентом в тестах), и вы, вероятно, получите альтернативные решения, которые доставят вас туда.