2016-01-09 5 views
3


Этот вопрос возник из первой части PowerMock + Robolectric + Dagger2
Так что я снова немного. Сожалею.

я проверить пользовательский класс представления, которые содержат:PowerMock + Robolectric + Dagger2. Часть I

  1. андроида элементы пользовательского интерфейса
  2. некоторой логику
  3. статических методов призваний
  4. зависимости dagger2


Так я использую следующие инструменты для испытания

  1. Robolectric для элементов пользовательского интерфейса насмешливых
  2. модульных тестов для логического тестирования
  3. PowerMock для статических методов насмешливых

Robolectric + PowerMock проблема интеграции известна и решение, как известно, - https://github.com/robolectric/robolectric/wiki/Using-PowerMock
Но с этим решением проблемы с кинжалом2 терпят неудачу.

Внимание к коду
Мой заказ вид - ProgressTextView:

public class ProgressTextView extends TextView { 

    private String defaultText; 
    private int fileSize; 
    private String fileSizeString; 
    private FileDownloaderI fileDownloader; 

    @Inject 
    FileDownloaderManager fileDownloaderManager; 

    Subscription downloadProgressChannelSubscription; 
    Subscription downloadCancelChannelSubscription; 

    public ProgressTextView(Context context) { 
     super(context); 
     provideDependency(); 
    } 

    public ProgressTextView(Context context, AttributeSet attrs) { 
     super(context, attrs); 
     provideDependency(); 
    } 

    public ProgressTextView(Context context, AttributeSet attrs, int defStyleAttr) { 
     super(context, attrs, defStyleAttr); 
     provideDependency(); 
    } 

    private void provideDependency() { 
     ApplicationSIP.get().applicationComponent().inject(this); 
    } 

} 

ApplicationSIP:

public class ApplicationSIP extends Application { 

    public static volatile Context applicationContext; 

    @NonNull 
    private AppComponent appComponent; 

    @Override 
    public void onCreate() { 
     super.onCreate(); 
     applicationContext = getApplicationContext(); 
     Logger.registerLogger(this); 

     appComponent = prepareApplicationComponent().build(); 
     appComponent.inject(this); 
    } 

    @NonNull 
    protected DaggerAppComponent.Builder prepareApplicationComponent() { 
     return DaggerAppComponent.builder() 
       .appModule(new AppModule(getApplicationContext())) 
       .tGModule(new TGModule()); 
    } 

    @NonNull 
    public AppComponent applicationComponent() { 
     return appComponent; 
    } 

    @NonNull 
    public static ApplicationSIP get() { 
     return (ApplicationSIP) applicationContext.getApplicationContext(); 
    } 

} 

AppComponent:

@Component(modules = {AppModule.class, TGModule.class, MediaModule.class, StaticModule.class}) 
@Singleton 
public interface AppComponent { 
    void inject(ApplicationSIP applicationSIP); 
    void inject(ProgressDownloadView progressDownloadView); 
    void inject(ProgressTextView progressTextView); 
} 

И ProgressTextViewTest:

@RunWith(RobolectricUnitTestRunner.class) 
@PowerMockIgnore({ "org.mockito.*", "org.robolectric.*", "android.*" }) 
@PrepareForTest(Formatter.class) 
public class ProgressTextViewTest { 

    @Rule 
    public PowerMockRule rule = new PowerMockRule(); 
    Activity activity; 

    @Before 
    public void beforeTest() { 
     // PowerMockito 
     PowerMockito.mockStatic(Formatter.class); 
     Mockito.when(Formatter.formatFileSize(anyObject(), anyInt())).thenReturn(""); 
     // Robolectic 
     activity = Robolectric.setupActivity(Activity.class); 
    } 

    @Test 
    public void init_FileDownloaded() { 
     ProgressTextView progressTextView = new ProgressTextView(activity); 
     ... 
    } 
} 

Так что, когда я начать этот тест я получаю следующее исключение:

java.lang.NullPointerException 
at com.tg.osip.ApplicationSIP.get(ApplicationSIP.java:64) 
at com.tg.osip.ui.general.views.ProgressTextView.provideDependency(ProgressTextView.java:60) 
at com.tg.osip.ui.general.views.ProgressTextView.<init>(ProgressTextView.java:46) 
at com.tg.osip.ui.general.views.ProgressTextViewTest.init_FileDownloaded(ProgressTextViewTest.java:67) 
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50) 
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) 
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) 
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) 
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26) 
at org.powermock.modules.junit4.rule.PowerMockStatement$1.run(PowerMockRule.java:52) 
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
at org.powermock.reflect.internal.WhiteboxImpl.performMethodInvocation(WhiteboxImpl.java:1873) 
at org.powermock.reflect.internal.WhiteboxImpl.doInvokeMethod(WhiteboxImpl.java:773) 
at org.powermock.reflect.internal.WhiteboxImpl.invokeMethod(WhiteboxImpl.java:638) 
at org.powermock.reflect.Whitebox.invokeMethod(Whitebox.java:401) 
at org.powermock.classloading.ClassloaderExecutor.execute(ClassloaderExecutor.java:98) 
at org.powermock.classloading.ClassloaderExecutor.execute(ClassloaderExecutor.java:78) 
at org.powermock.modules.junit4.rule.PowerMockStatement.evaluate(PowerMockRule.java:49) 
at org.robolectric.RobolectricTestRunner$2.evaluate(RobolectricTestRunner.java:251) 
at org.robolectric.RobolectricTestRunner.runChild(RobolectricTestRunner.java:188) 
at org.robolectric.RobolectricTestRunner.runChild(RobolectricTestRunner.java:54) 
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) 
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) 
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) 
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) 
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) 
at org.robolectric.RobolectricTestRunner$1.evaluate(RobolectricTestRunner.java:152) 
at org.junit.runners.ParentRunner.run(ParentRunner.java:363) 
at org.junit.runner.JUnitCore.run(JUnitCore.java:137) 
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:78) 
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:212) 
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:68) 
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140) 

Если изменить robolectric активности инициализации размещение:

@RunWith(RobolectricUnitTestRunner.class) 
@PowerMockIgnore({ "org.mockito.*", "org.robolectric.*", "android.*" }) 
@PrepareForTest(Formatter.class) 
public class ProgressTextViewTest { 

    @Rule 
    public PowerMockRule rule = new PowerMockRule(); 
    Activity activity = Robolectric.setupActivity(Activity.class); 

    @Before 
    public void beforeTest() { 
     // PowerMockito 
     PowerMockito.mockStatic(Formatter.class); 
     Mockito.when(Formatter.formatFileSize(anyObject(), anyInt())).thenReturn(""); 
    } 

    @Test 
    public void init_FileDownloaded() { 
     ProgressTextView progressTextView = new ProgressTextView(activity); 
     ... 
    } 
} 

Я получаю другое исключение:

java.lang.OutOfMemoryError: Java heap space 
at java.util.Arrays.copyOf(Arrays.java:3332) 
at java.lang.AbstractStringBuilder.expandCapacity(AbstractStringBuilder.java:137) 
at java.lang.AbstractStringBuilder.ensureCapacityInternal(AbstractStringBuilder.java:121) 
at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:569) 
at java.lang.StringBuffer.append(StringBuffer.java:369) 
at java.io.StringWriter.write(StringWriter.java:94) 
at com.thoughtworks.xstream.core.util.QuickWriter.flush(QuickWriter.java:73) 
at com.thoughtworks.xstream.io.xml.PrettyPrintWriter.flush(PrettyPrintWriter.java:342) 
at com.thoughtworks.xstream.XStream.toXML(XStream.java:858) 
at com.thoughtworks.xstream.XStream.toXML(XStream.java:843) 
at org.powermock.classloading.DeepCloner.clone(DeepCloner.java:53) 
at org.powermock.classloading.ClassloaderExecutor.execute(ClassloaderExecutor.java:89) 
at org.powermock.classloading.ClassloaderExecutor.execute(ClassloaderExecutor.java:78) 
at org.powermock.modules.junit4.rule.PowerMockStatement.evaluate(PowerMockRule.java:49) 
at org.robolectric.RobolectricTestRunner$2.evaluate(RobolectricTestRunner.java:251) 
at org.robolectric.RobolectricTestRunner.runChild(RobolectricTestRunner.java:188) 
at org.robolectric.RobolectricTestRunner.runChild(RobolectricTestRunner.java:54) 
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) 
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) 
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) 
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) 
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) 
at org.robolectric.RobolectricTestRunner$1.evaluate(RobolectricTestRunner.java:152) 
at org.junit.runners.ParentRunner.run(ParentRunner.java:363) 
at org.junit.runner.JUnitCore.run(JUnitCore.java:137) 
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:68) 
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
+0

Часть I и часть II это как звездные войны: D –

+0

@MsYvette yep;) –

ответ

2

Прежде чем отвечать на ваш вопрос. Я бы сказал:

  1. Ваш взгляд делает/зная слишком много.Я говорю о знании FileDownloaderManager и знаниях о том, как получить зависимости
  2. Поскольку вы используете инъекцию, я бы перенес статические функции в класс и вставлял их. Будет намного проще писать/поддерживать тесты
  3. Даже название класса AppComponent говорит, что он не должен знать, как вводить представление. Подумайте о дозированных инъекциях
  4. Некоторые несовершеннолетние с applicationContext. Почему это volatile, вы ожидаете, что он будет доступен из не основной темы? Это уже ApplicationSIP, зачем вам играть в контекст приложения и кастинг?

И, наконец, ответ. Первая трассировка стека говорит, что appContext имеет значение NULL. Так что onCreate вашего приложения не было вызвано. Я не вижу код RobolectricUnitTestRunner, но я предполагаю, что проблема связана с использованием PowerMock. Для этого доказано второе доказательство стека. Поэтому я бы сказал, что ответ заключается в прекращении использования PowerMock.

+0

Спасибо, Eugen, за ответ!) Да, возможно, мой взгляд слишком много. Но эти взгляды находятся в одном из ViewHolders в RecyclerAdapter RecyclerView. Если я нажму на это представление, я хочу загрузить файл. Таким образом, представление должно показать прогресс и результат загрузки. Я не знаю, как получить представление из recyclerView или recyclerAdapter и исправить его обновление без обновления полного ViewHolder. Итак, для докладчиков и взаимодействий во фрагменте я использую подкомпонент. Да, это удобно –

+0

Теперь я использую класс упаковки для статических методов и закачиваю его) –

+0

Об изменчивости. Это дополнительный код. –

1

Резюме
Не используйте PowerMock с Robolectric и Dagger2. Это небезопасно.
Теперь я использую классы переноса для статических методов и вводя эти классы с помощью Dagger2. Поэтому в моем классе тестирования нет статических методов, и PowerMock не нужен.
Я думаю, что это вполне нормальный вариант.
И спасибо Евгению Мартынову за помощь.