2013-06-13 3 views
2

Я только что обновился до Robolectric 2.1.1 и интегрировал Picasso сегодня. У меня теперь есть два тестовых примера, которые случайно случаются (один из этих фрагментов даже не использует Picasso). Если я буду продолжать тесты, все обычно заканчивается (может занять несколько попыток).Ошибки ложных тестов с использованием Picasso и Robolectric

Тест

@Before 
public void setUp() throws Exception 
{ 
    detailActivity = Robolectric.buildActivity(ActivityUnderTest.class) 
           .withIntent(createIntent()) 
           .create() 
           .start() 
           .resume() 
           .get(); 

    // Note: The other test case doesn't use the fancy withIntent() doohickey 
} 

public static Intent createIntent() 
{ 
    Bundle bundle = DetailFragment.createBundle(getTestData()); 
    Intent intent = new Intent(new ActivityUnderTest(), Activity.class); 
    intent.putExtras(bundle); 
    return intent; 
} 

@Test 
public void shouldNotBeNull() throws Exception 
{ 
    assertNotNull(detailActivity); 
} 

Codez

Я посылаю в пачке информации к деятельности, которая в основном пустая оболочка. Действие отображает фрагмент через XML. В моем фрагменте я получаю данные из пакета, используя getActivity().getIntent().getExtras().

Лежа Предупреждение

[WARN] Вы инстанцировании активность (com.colabug.project.singlepanel.ActivityUnderTest) непосредственно; вместо этого используйте Robolectric.buildActivity().

StackTrace

java.lang.RuntimeException: An unexpected exception occurred 
at com.squareup.picasso.Request$1.run(Request.java:114) 
at org.robolectric.util.Scheduler$PostedRunnable.run(Scheduler.java:162) 
at org.robolectric.util.Scheduler.runOneTask(Scheduler.java:107) 
at org.robolectric.util.Scheduler.advanceTo(Scheduler.java:92) 
at org.robolectric.util.Scheduler.advanceToLastPostedRunnable(Scheduler.java:68) 
at org.robolectric.util.Scheduler.unPause(Scheduler.java:25) 
at org.robolectric.shadows.ShadowLooper.unPause(ShadowLooper.java:219) 
at org.robolectric.shadows.ShadowLooper.runPaused(ShadowLooper.java:258) 
at org.robolectric.util.ActivityController.invokeWhilePaused(ActivityController.java:202) 
at org.robolectric.util.ActivityController.start(ActivityController.java:144) 
at com.colabug.project.singlepanel.DetailActivityTest.setUp(DetailActivityTest.java:32) 
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) 
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) 
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44) 
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15) 
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41) 
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:27) 
at org.robolectric.RobolectricTestRunner$2.evaluate(RobolectricTestRunner.java:241) 
at org.junit.runners.BlockJUnit4ClassRunner.runNotIgnored(BlockJUnit4ClassRunner.java:79) 
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:71) 
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:49) 
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193) 
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52) 
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191) 
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42) 
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184) 
at org.robolectric.RobolectricTestRunner$1.evaluate(RobolectricTestRunner.java:177) 
at org.junit.runners.ParentRunner.run(ParentRunner.java:236) 
at org.junit.runners.Suite.runChild(Suite.java:128) 
at org.junit.runners.Suite.runChild(Suite.java:24) 
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193) 
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52) 
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191) 
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42) 
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184) 
at org.junit.runners.ParentRunner.run(ParentRunner.java:236) 
at org.junit.runner.JUnitCore.run(JUnitCore.java:157) 
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:77) 
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:195) 
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:63) 
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) 
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120) 
Caused by: java.lang.NullPointerException: Bitmap config was null. 
at org.robolectric.shadows.ShadowBitmap.getBytesPerPixel(ShadowBitmap.java:338) 
at org.robolectric.shadows.ShadowBitmap.getRowBytes(ShadowBitmap.java:225) 
at org.robolectric.shadows.ShadowBitmap.getByteCount(ShadowBitmap.java:230) 
at android.graphics.Bitmap.getByteCount(Bitmap.java) 
at com.squareup.picasso.Utils$BitmapHoneycombMR1.getByteCount(Utils.java:250) 
at com.squareup.picasso.Utils.getBitmapBytes(Utils.java:65) 
at com.squareup.picasso.Stats.processBitmap(Stats.java:64) 
at com.squareup.picasso.Stats.bitmapDecoded(Stats.java:40) 
at com.squareup.picasso.Picasso.loadFromType(Picasso.java:365) 
at com.squareup.picasso.Picasso.resolveRequest(Picasso.java:215) 
at com.squareup.picasso.Picasso.run(Picasso.java:197) 
at com.squareup.picasso.Request.run(Request.java:108) 
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:439) 
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303) 
at java.util.concurrent.FutureTask.run(FutureTask.java:138) 
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895) 
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918) 
at java.lang.Thread.run(Thread.java:680) 
at com.squareup.picasso.Utils$PicassoThread.run(Utils.java:244) 

pom.xml

<?xml version="1.0" encoding="UTF-8"?> 
<project 
    xmlns="http://maven.apache.org/POM/4.0.0" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> 

    <modelVersion>4.0.0</modelVersion> 
    <groupId>com.colabug</groupId> 
    <artifactId>Project</artifactId> 
    <version>1.0.0-SNAPSHOT</version> 
    <packaging>apk</packaging> 
    <name>Project</name> 

    <dependencies> 
     <dependency> 
      <groupId>com.google.android</groupId> 
      <artifactId>android</artifactId> 
      <version>2.2.1</version> 
      <scope>provided</scope> 
     </dependency> 

     <!-- Make sure this is below the android dependencies --> 
     <dependency> 
      <groupId>junit</groupId> 
      <artifactId>junit</artifactId> 
      <version>4.8.2</version> 
      <scope>test</scope> 
     </dependency> 

     <dependency> 
      <groupId>org.robolectric</groupId> 
      <artifactId>robolectric</artifactId> 
      <version>2.1.1</version> 
      <scope>test</scope> 
     </dependency> 

     <dependency> 
      <groupId>com.squareup.picasso</groupId> 
      <artifactId>picasso</artifactId> 
      <version>1.0.2</version> 
     </dependency> 
    </dependencies> 

    <build> 
     <finalName>${project.artifactId}</finalName> 

     <plugins> 
      <plugin> 
       <!-- See http://code.google.com/p/maven-android-plugin/ --> 
       <groupId>com.jayway.maven.plugins.android.generation2</groupId> 
       <artifactId>maven-android-plugin</artifactId> 
       <version>2.8.3</version> 
       <configuration> 
        <sdk> 
         <platform>17</platform> 
        </sdk> 
       </configuration> 
       <extensions>true</extensions> 
      </plugin> 
     </plugins> 
    </build> 
</project> 

Любые идеи? IntelliJ может быть причиной, так как он отображается в стеке. Я использовал mvn clean и вручную очистил автоматически сгенерированные файлы в командной строке и перестроил проект в IntelliJ.

ответ

1

Предупреждение не лежит.

Intent intent = new Intent (новый ActivityUnderTest(), Activity.class);

«new ActivityUnderTest()« квалифицируется как «непосредственное создание операции».

Во многих случаях, когда тесты терпят неудачу/проходят кажущиеся-случайным образом, в базовом коде есть проблема с потоками. В прошлый раз, когда это случилось со мной, тест «иногда это не сработал» фактически показывал условие гонки в моем коде очереди.

Я нахожу, что когда у меня возникает реакция «этот тест глуп!» Я почти обнаружил, что тест на самом деле умнее меня (и лучше меня, так как он пытается быть полезным).

+0

Ах, хороший улов. Рад, что я включил предупреждение, которое, как я думал, не имел никакого отношения. Попробуем завтра! – colabug

3

Drew правильный. NPE происходит в фоновом потоке.

Вызвано: java.lang.NullPointerException: Конфигурация Bitmap была нулевой.

По сути, это, по-видимому, проблема с ShadowBitmap. Однако решением, которое я выбрал, было создание класса MockPicasso.

Выполнение заглушки предотвращает NPE. Это также имеет дополнительное преимущество, предотвращая, чтобы модульные тесты запрашивали растровые изображения по сети в первую очередь.

MockPicasso.java

package com.squareup.picasso; 

import android.graphics.Bitmap; 
import android.widget.ImageView; 

public class MockPicasso extends Picasso { 
    private static String lastImagePath = null; 
    private static ImageView lastTargetImageView = null; 

    MockPicasso() { 
     super(null, null, null, Cache.NONE, null, new MockStats()); 
    } 

    public static void init() { 
     singleton = new MockPicasso(); 
    } 

    public static String getLastImagePath() { 
     return lastImagePath; 
    } 

    public static ImageView getLastTargetImageView() { 
     return lastTargetImageView; 
    } 

    @Override 
    public RequestBuilder load(String path) { 
     lastImagePath = path; 
     return new MockRequestBuilder(); 
    } 

    class MockRequestBuilder extends RequestBuilder { 
     @Override 
     public void into(ImageView target) { 
      lastTargetImageView = target; 
     } 
    } 

    static class MockStats extends Stats { 
     MockStats() { 
      super(Cache.NONE); 
     } 

     @Override 
     void bitmapDecoded(Bitmap bitmap) { 
      // Do nothing. 
     } 
    } 
} 

Использование getLastImagePath() и getLastTargetImageView() вы можете проверить ваш код запроса правильное изображение и загрузить его в правильном зрения фактически не попав в сеть.

MyActivity.java

@Override 
protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.main); 
    ImageView avatar = (ImageView) findViewById(R.id.avatar); 
    String path = getIntent().getStringExtra("avatar_url"); 
    Picasso.with(this).load(path).into(avatar); 
} 

MyActivityTest.java

@Test 
public void shouldDisplayAvatar() throws Exception { 
    MockPicasso.init(); 
    String imageUrl = "http://www.example.com/test.jpg"; 
    Intent intent = new Intent().putExtra("avatar_url", imageUrl); 
    MyActivity myActivity = Robolectric.buildActivity(MyActivity.class) 
      .create().get(); 

    myActivity.setIntent(intent); 
    Robolectric.shadowOf(myActivity).callOnCreate(null); 
    ImageView avatar = (ImageView) myActivity.findViewById(R.id.avatar); 
    assertThat(MockPicasso.getLastImagePath()).isEqualTo(imageUrl); 
    assertThat(MockPicasso.getLastTargetImageView()).isSameAs(avatar); 
} 
+0

Спасибо за всю информацию Chuck! Вы проверите это в этот уик-энд и посмотрите, исправляет ли он мою ошибку. – colabug

+0

Надеюсь, это помогло. Вот [сообщение в блоге] (https://engineering.aweber.com/unit-testing-remote-images-on-android-with-picasso-and-robolectric/) Я написал более подробную информацию и немного больше в пример. – ecgreb

+0

@ecgreb: Как вы делаете MockPicasso частью пакета com.squareup.picasso? –

 Смежные вопросы

  • Нет связанных вопросов^_^