在使用Robolectric测试Android应用程序时,如何创建影子类以解决与自定义属性相关的崩溃问题?

col*_*bug 10 android unit-testing robolectric

我正在将自定义小部件集成到我的项目中.它使用自定义属性并且正在崩溃Robolectric.从我收集的内容来看,还不支持自定义属性.注意:构造函数是"敌对的",因为它会在构造时抛出异常,但我现在已将它们注释掉了.

崩溃日志

java.lang.RuntimeException:在com.xtremelabs.robolectric.res.ViewLoader.inflateView(ViewLoader.java:82)的com.xtremelabs.robolectric.res.ViewLoader.inflateView(ViewLoader.java:106)中错误膨胀layout/main com.xtremelabs.robolectric.res.ViewLoader.inflateView(ViewLoader.java:86)位于com.xtremelabs.robolectric.res.ResourceLoader.inflateView(ResourceLoader.java:377)com.xtremelabs.robolectric.shadows.ShadowLayoutInflater.inflate( ShadowLayoutInflater.java:43)位于com.xtremelabs.robolectric.shadows.ShadowActivity.setContentView的android.view.LayoutInflater.inflate(LayoutInflater.java)中的com.xtremelabs.robolectric.shadows.ShadowLayoutInflater.inflate(ShadowLayoutInflater.java:48) (ShadowActivity.java:101)位于com.blah.MainActivity.estCreate(MainActivity.java:17)的com.blah.MainActivityTest.setUp(MainActivityTest.java:29)上的android.app.Activity.setContentView(Activity.java)在org.junit.interna的org.junit.runners.model.FrameworkMethod $ 1.runReflectiveCall(FrameworkMethod.java:44)l.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)org.junit.internal.runners.statements.RunBefores.evaluate( RunBefores.java:27)

引起:java.lang.ClassCastException:com.blah.support.shadows.ShadowMultiDirectionSlidingDrawer无法转换为com.xtremelabs.robolectric.Robolectric.shadowOf(Robolectric.java:857)的com.xtremelabs.robolectric.shadows.ShadowView位于com.xtremelabs.robolectric.shadows.ShadowViewGroup.addView(ShadowViewGroup.java:60)的android.view.ViewGroup.addView(ViewGroup.java)中的.xtremelabs.robolectric.shadows.ShadowViewGroup.addView(ShadowViewGroup.java:70)at com.xtremelabs.robolectric.res.ViewLoader上的com.xtremelabs.robolectric.res.ViewLoader $ ViewNode.addToParent(ViewLoader.java:217)中的android.view.ViewGroup.addView(ViewGroup.java)$ ViewNode.create(ViewLoader. java:180)at com.xtremelabs.robolectric.res.ViewLoader $ ViewNode.inflate(ViewLoader.java:150)at com.xtremelabs.robolectric.res.ViewLoader $ ViewNode.inflate(ViewLoader.java:153)at com.xtremelabs .robolectric.res.ViewLoader.inflateView(ViewLoader.java:102)... 29更多

我正在努力解决这个问题,因为我不太关心测试这个小部件.基本上我希望我的测试不会崩溃并验证视图元素是否出现在屏幕上.

有人建议将java文件放在android包中,但我不确定它是否适用于我的情况.正如这个答案所暗示的那样,自定义小部件存在于"android"包中,它与我的com.blah结构平行.

我创建了一个小部件的阴影来解决敌意问题(但目前我只是注释掉异常抛出).最初我想绕过构造函数中正在进行的工作,因为它依赖于Robolectric未正确报告的属性.阴影构造函数被调用,但它继续通过正常的构造函数执行.有没有办法绕过额外的建设?

ShadowClass

@Implements (MultiDirectionSlidingDrawer.class)
public class ShadowMultiDirectionSlidingDrawer
{
    public void __constructor__( Context context, AttributeSet attrs )
    {
    }

    public void __constructor__( Context context, AttributeSet attrs, int defStyle )
    {
    }
}
Run Code Online (Sandbox Code Playgroud)

自定义测试运行器

public class CustomTestRunner extends RobolectricTestRunner 
{
    public CustomTestRunner( Class<?> testClass ) throws InitializationError
    {
        super( testClass );
        addClassOrPackageToInstrument("android");
    }

    @Override
    protected void bindShadowClasses()
    {
        super.bindShadowClasses();
        Robolectric.bindShadowClass( ShadowMultiDirectionSlidingDrawer.class );
    }
}
Run Code Online (Sandbox Code Playgroud)

在测试框架支持此问题之前,这是解决崩溃的正确方法吗?我的阴影做错了还是我错过了别的什么?

col*_*bug 4

所以我用一个简单的方法解决了这个问题。我没有将视图作为 main.xml 的一部分进行扩展,而是将其放入单独的布局文件中。在我的活动的构造函数中,我在受保护的函数中膨胀了布局。在我的测试类中,我扩展了被测类,并且没有膨胀视图元素,而是使用布尔值来跟踪所调用的函数。

MainActivity.java

public class MainActivity extends FragmentActivity
{
    @Override
    public void onCreate( Bundle savedInstanceState )
    {
        super.onCreate( savedInstanceState );
        setContentView( R.layout.main );
        addOptionsShade();
    }

    protected void addOptionsShade()
    {
        ViewGroup viewGroup = (ViewGroup) findViewById( R.id.main_view );
        View view = getLayoutInflater().inflate( R.layout.options_shade, null );
        viewGroup.addView( view );
    }
}
Run Code Online (Sandbox Code Playgroud)

MainActivityTest.java

@Test
public void shouldHaveOptionsShade() throws Exception
{
    assertTrue( mainActivity.hostileLibraryWasCalled );
}

class TestMainActivity extends MainActivity
{
    boolean hostileLibraryWasCalled = false;

    @Override
    protected void addOptionsShade()
    {
        hostileLibraryWasCalled = true;
    }
}
Run Code Online (Sandbox Code Playgroud)

我删除了影子类和绑定,并将库放回到一个合理的位置(不在 android 包中)。

  • 作弊...工程...有什么区别?:) (7认同)
  • 这不是作弊吗?...为测试而保护方法。 (2认同)