5

con un normale android.app.AlertDialog opere con ShadowAlertDialog.getLatestAlertDialog(), ma se si utilizza una libreria di supporto android.support.v7.app.AlertDialog, quindi questa eccezione accade:Robolectric InflateException quando si utilizza libreria di supporto v7 AlertDialog

android.view.InflateException: XML file app/build/intermediates/res/qa/debug/layout/abc_alert_dialog_material.xml line #-1 (sorry, not yet implemented): Error inflating class android.support.v7.internal.widget.DialogTitle 
    at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:713) 
    at android.view.LayoutInflater.rInflate(LayoutInflater.java:755) 
    at android.view.LayoutInflater.rInflate(LayoutInflater.java:758) 
    at android.view.LayoutInflater.rInflate(LayoutInflater.java:758) 
    at android.view.LayoutInflater.inflate(LayoutInflater.java:492) 
    at uk.co.chrisjenx.calligraphy.CalligraphyLayoutInflater.inflate(CalligraphyLayoutInflater.java:60) 
    at android.view.LayoutInflater.inflate(LayoutInflater.java:397) 
    at android.view.LayoutInflater.inflate(LayoutInflater.java:353) 
    at android.support.v7.app.AppCompatDelegateImplV7.setContentView(AppCompatDelegateImplV7.java:249) 
    at android.support.v7.app.AppCompatDialog.setContentView(AppCompatDialog.java:75) 
    at android.support.v7.app.AlertController.installContent(AlertController.java:216) 
    at android.support.v7.app.AlertDialog.onCreate(AlertDialog.java:240) 
    at android.app.Dialog.dispatchOnCreate(Dialog.java:361) 
    at android.app.Dialog.show(Dialog.java:262) 
    at org.robolectric.shadows.ShadowDialog.show(ShadowDialog.java:65) 
    at android.app.Dialog.show(Dialog.java) 
<snip> 
Caused by: java.lang.StringIndexOutOfBoundsException: String index out of range: -9 
    at java.lang.String.substring(String.java:1955) 
    at org.robolectric.res.ResName.qualifyResName(ResName.java:51) 
    at org.robolectric.res.Attribute.getStyleReference(Attribute.java:147) 
    at org.robolectric.res.builder.XmlFileBuilder$XmlResourceParserImpl.getResourceId(XmlFileBuilder.java:789) 

Questo è un problema noto, ma qual è la migliore modo di risolvere il problema?
https://github.com/robolectric/robolectric/issues/1736

risposta

4

Io uso un programma di utilità statica per costruire la mia AlertDialog oggetti, e ho costruire un android.app.AlertDialog uno quando rilevo Robolectric nel classpath. Ecco il mio codice:

private static Boolean isRobolectricTest = null; 

/** 
* Determines if we are running inside of Robolectric or not. 
*/ 
public static boolean isARobolectricUnitTest() { 
    if (isRobolectricTest == null) { 
     try { 
      Class.forName("org.robolectric.Robolectric"); 
      isRobolectricTest = true; 
     } catch (ClassNotFoundException e) { 
      isRobolectricTest = false; 
     } 
    } 
    return isRobolectricTest; 
} 

/** 
* This utility helps us to workaround a Robolectric issue that causes our unit tests to fail 
* when an Activity/Fragment creates an AlertDialog using the v7 support library. The 
* workaround is to use the normal android.app.AlertDialog when running Robolectric tests. 
* 
* The Robolectric bug is: https://github.com/robolectric/robolectric/issues/1736 
* android.view.InflateException: XML file app/build/intermediates/res/qa/debug/layout/abc_alert_dialog_material.xml line #-1 (sorry, not yet implemented): Error inflating class android.support.v7.internal.widget.DialogTitle 
*/ 
public static DialogInterface createAndShowDialog(Context context, 
                @StringRes int titleResId, 
                String message, 
                @StringRes int negativeTextResId, 
                DialogInterface.OnClickListener negativeClickListener, 
                @StringRes int neutralTextResId, 
                DialogInterface.OnClickListener neutralClickListener, 
                @StringRes int positiveTextResId, 
                DialogInterface.OnClickListener positiveClickListener, 
                boolean cancelable) { 
    if (isARobolectricUnitTest()) { 
     return UiUtils.createDialog(context, titleResId, message, negativeTextResId, negativeClickListener, neutralTextResId, neutralClickListener, positiveTextResId, positiveClickListener, cancelable); 
    } else { 
     return UiUtils.createDialogSupportV7(context, titleResId, message, negativeTextResId, negativeClickListener, neutralTextResId, neutralClickListener, positiveTextResId, positiveClickListener, cancelable); 
    } 
} 

private static android.app.AlertDialog createDialog(Context context, 
                @StringRes int titleResId, 
                String message, 
                @StringRes int negativeTextResId, 
                DialogInterface.OnClickListener negativeClickListener, 
                @StringRes int neutralTextResId, 
                DialogInterface.OnClickListener neutralClickListener, 
                @StringRes int positiveTextResId, 
                DialogInterface.OnClickListener positiveClickListener, 
                boolean cancelable) { 
    android.app.AlertDialog.Builder builder = new android.app.AlertDialog.Builder(context); 
    builder.setTitle(titleResId); 
    builder.setMessage(message); 
    builder.setNegativeButton(negativeTextResId, negativeClickListener); 

    if ((neutralTextResId != -1) && (neutralClickListener != null)) { 
     builder.setNeutralButton(neutralTextResId, neutralClickListener); 
    } 

    builder.setPositiveButton(positiveTextResId, positiveClickListener); 
    builder.setCancelable(cancelable); 

    android.app.AlertDialog alertDialog = builder.create(); 
    alertDialog.show(); 

    return alertDialog; 
} 

private static android.support.v7.app.AlertDialog createDialogSupportV7(Context context, 
                     @StringRes int titleResId, 
                     String message, 
                     @StringRes int negativeTextResId, 
                     DialogInterface.OnClickListener negativeClickListener, 
                     @StringRes int neutralTextResId, 
                     DialogInterface.OnClickListener neutralClickListener, 
                     @StringRes int positiveTextResId, 
                     DialogInterface.OnClickListener positiveClickListener, 
                     boolean cancelable) { 
    android.support.v7.app.AlertDialog.Builder builder = new android.support.v7.app.AlertDialog.Builder(context); 
    builder.setTitle(titleResId); 
    builder.setMessage(message); 
    builder.setNegativeButton(negativeTextResId, negativeClickListener); 

    if ((neutralTextResId != -1) && (neutralClickListener != null)) { 
     builder.setNeutralButton(neutralTextResId, neutralClickListener); 
    } 

    builder.setPositiveButton(positiveTextResId, positiveClickListener); 
    builder.setCancelable(cancelable); 

    android.support.v7.app.AlertDialog alertDialog = builder.create(); 
    alertDialog.show(); 

    return alertDialog; 
} 

Non è l'ideale, ma fa il lavoro, ed è facile da rimuovere l'hack più tardi, quando il problema è stato risolto Robolectric.