Skip to content

Instantly share code, notes, and snippets.

@JakeWharton
Created September 29, 2012 05:42
Show Gist options
  • Star 15 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save JakeWharton/3803294 to your computer and use it in GitHub Desktop.
Save JakeWharton/3803294 to your computer and use it in GitHub Desktop.
Making Robolectric suck less... (barely)

You need to do this once in your base test runner:

ActionBarSherlock.registerImplementation(ActionBarSherlockRobolectric.class);

and your Robolectric should have this patch:

https://github.com/square/robolectric/commit/fac24e5ef6d5830e6e67ad27aff2f8f57cedb5a1
// Copyright 2012 Square, Inc.
package com.squareup.test;
import android.app.Activity;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import com.actionbarsherlock.ActionBarSherlock;
import com.actionbarsherlock.app.ActionBar;
import com.actionbarsherlock.internal.ActionBarSherlockCompat;
import com.actionbarsherlock.internal.ActionBarSherlockNative;
import static com.xtremelabs.robolectric.Robolectric.shadowOf;
/**
* During initialization, {@link ActionBarSherlock} figures out which {@link
* com.actionbarsherlock.app.ActionBar} to use based on the API level. It does this by checking the
* Build.Version.SDK_INT value which depends on the hidden <i>SystemProperties</i> class.
*
* Because Roboelectric does not have this, it always returns <code>0</code> for its API level
* causing {@link ActionBarSherlock} to crash. This class helps resolve this issue by providing
* an {@link ActionBarSherlockNative} implementation for API level 0.
* @see ActionBarSherlock#registerImplementation(Class)
*/
@ActionBarSherlock.Implementation(api = 0)
public class ActionBarSherlockRobolectric extends ActionBarSherlockCompat {
final private ActionBar actionBar;
public ActionBarSherlockRobolectric(Activity activity, int flags) {
super(activity, flags);
actionBar = new MockActionBar(activity);
}
@Override public void setContentView(int layoutResId) {
LayoutInflater layoutInflater = LayoutInflater.from(mActivity);
View contentView = layoutInflater.inflate(layoutResId, null);
shadowOf(mActivity).setContentView(contentView);
}
@Override public void setContentView(View view) {
shadowOf(mActivity).setContentView(view);
}
@Override public ActionBar getActionBar() {
return actionBar;
}
@Override protected Context getThemedContext() {
return mActivity;
}
}
// Copyright 2012 Square, Inc.
package com.squareup.test;
import com.squareup.test.actionbarsherlock.SherlockResourceLoader;
import com.xtremelabs.robolectric.RobolectricConfig;
import com.xtremelabs.robolectric.RobolectricTestRunner;
import com.xtremelabs.robolectric.bytecode.RobolectricClassLoader;
import com.xtremelabs.robolectric.bytecode.ShadowWrangler;
import com.xtremelabs.robolectric.res.ResourceLoader;
import java.util.Arrays;
import org.junit.runners.model.InitializationError;
/**
* {@link RobolectricTestRunner} primarily used to provide a custom {@link
* RobolectricClassLoader} for instrumenting our own packages. It also provides a
* custom {@link ResourceLoader} to load ActionBarSherlock menus.
*/
public class ActionBarSherlockTestRunner extends RobolectricTestRunner {
private static RobolectricClassLoader classLoader;
protected ActionBarSherlockTestRunner(Class<?> testClass, RobolectricConfig robolectricConfig)
throws InitializationError {
super(testClass, ShadowWrangler.getInstance(), getClassLoader(), robolectricConfig);
}
/** Use this to add more packages that you want to be instrumented by Robolectric. */
private static RobolectricClassLoader getClassLoader() {
// Please don't cry.
if (classLoader == null && !isInstrumented()) {
classLoader = new RobolectricClassLoader(ShadowWrangler.getInstance(),
Arrays.asList("com.actionbarsherlock.app", "com.actionbarsherlock.view"));
}
return classLoader;
}
/** Return a {@link SherlockResourceLoader} instead, which loads ABS menus for testing. */
@Override protected ResourceLoader createResourceLoader(RobolectricConfig robolectricConfig) {
ResourceLoader resourceLoader = resourceLoaderForRootAndDirectory.get(robolectricConfig);
if (resourceLoader == null) {
try {
robolectricConfig.validate();
String rClassName = robolectricConfig.getRClassName();
Class rClass = Class.forName(rClassName);
resourceLoader = new SherlockResourceLoader(robolectricConfig.getRealSdkVersion(), rClass,
robolectricConfig.getResourcePath(), robolectricConfig.getAssetsDirectory());
resourceLoaderForRootAndDirectory.put(robolectricConfig, resourceLoader);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
resourceLoader.setStrictI18n(robolectricConfig.getStrictI18n());
return resourceLoader;
}
}
// Copyright 2012 Square, Inc.
package com.squareup.test;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.view.View;
import android.widget.SpinnerAdapter;
import com.actionbarsherlock.app.ActionBar;
public class MockActionBar extends ActionBar {
String title;
String subtitle;
View customView;
Context realContext;
public MockActionBar(Context context) {
realContext = context;
}
@Override public void setCustomView(View view) {
setCustomView(view, null);
}
@Override public void setCustomView(View view, LayoutParams layoutParams) {
this.customView = view;
}
@Override public void setCustomView(int resId) {
}
@Override public void setIcon(int resId) {
}
@Override public void setIcon(Drawable icon) {
}
@Override public void setLogo(int resId) {
}
@Override public void setLogo(Drawable logo) {
}
@Override
public void setListNavigationCallbacks(SpinnerAdapter adapter, OnNavigationListener callback) {
}
@Override public void setSelectedNavigationItem(int position) {
}
@Override public int getSelectedNavigationIndex() {
return 0;
}
@Override public int getNavigationItemCount() {
return 0;
}
@Override public void setTitle(CharSequence title) {
this.title = (String) title;
}
@Override public void setTitle(int resId) {
title = realContext.getString(resId);
}
@Override public void setSubtitle(CharSequence newSubtitle) {
subtitle = (String) newSubtitle;
}
@Override public void setSubtitle(int resId) {
subtitle = realContext.getString(resId);
}
@Override public void setDisplayOptions(int options) {
}
@Override public void setDisplayOptions(int options, int mask) {
}
@Override public void setDisplayUseLogoEnabled(boolean useLogo) {
}
@Override public void setDisplayShowHomeEnabled(boolean showHome) {
}
@Override public void setDisplayHomeAsUpEnabled(boolean showHomeAsUp) {
}
@Override public void setDisplayShowTitleEnabled(boolean showTitle) {
}
@Override public void setDisplayShowCustomEnabled(boolean showCustom) {
}
@Override public void setBackgroundDrawable(Drawable d) {
}
@Override public View getCustomView() {
return customView;
}
@Override public CharSequence getTitle() {
return title;
}
@Override public CharSequence getSubtitle() {
return subtitle;
}
@Override public int getNavigationMode() {
return 0;
}
@Override public void setNavigationMode(int mode) {
}
@Override public int getDisplayOptions() {
return 0;
}
@Override public Tab newTab() {
return null;
}
@Override public void addTab(Tab tab) {
}
@Override public void addTab(Tab tab, boolean setSelected) {
}
@Override public void addTab(Tab tab, int position) {
}
@Override public void addTab(Tab tab, int position, boolean setSelected) {
}
@Override public void removeTab(Tab tab) {
}
@Override public void removeTabAt(int position) {
}
@Override public void removeAllTabs() {
}
@Override public void selectTab(Tab tab) {
}
@Override public Tab getSelectedTab() {
return null;
}
@Override public Tab getTabAt(int index) {
return null;
}
@Override public int getTabCount() {
return 0;
}
@Override public int getHeight() {
return 0;
}
@Override public void show() {
}
@Override public void hide() {
}
@Override public boolean isShowing() {
return false;
}
@Override public void addOnMenuVisibilityListener(OnMenuVisibilityListener listener) {
}
@Override
public void removeOnMenuVisibilityListener(OnMenuVisibilityListener listener) {
}
}
// Copyright 2012 Square, Inc.
package com.squareup.test.actionbarsherlock;
import com.actionbarsherlock.app.ActionBar;
import com.actionbarsherlock.app.SherlockFragmentActivity;
import com.actionbarsherlock.view.MenuInflater;
import com.squareup.test.MockActionBar;
import com.xtremelabs.robolectric.internal.Implementation;
import com.xtremelabs.robolectric.internal.Implements;
import com.xtremelabs.robolectric.shadows.ShadowFragmentActivity;
@Implements(SherlockFragmentActivity.class)
public class ShadowSherlockFragmentActivity extends ShadowFragmentActivity {
private ActionBar actionBar;
@Implementation
public ActionBar getSupportActionBar() {
if (actionBar == null) {
actionBar = new MockActionBar(getApplicationContext());
}
return actionBar;
}
@Implementation
public MenuInflater getSupportMenuInflater() {
return new SherlockMenuInflater(getApplicationContext());
}
}
// Copyright 2012 Square, Inc.
package com.squareup.test.actionbarsherlock;
import android.content.Context;
import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuInflater;
import static com.xtremelabs.robolectric.Robolectric.shadowOf;
/**
* Inflates menus that are part of ActionBarSherlock instead. Uses ABS custom {@link
* com.actionbarsherlock.app.view.Menu} instead of the stock one.
*/
public class SherlockMenuInflater extends MenuInflater {
private final Context context;
public SherlockMenuInflater(Context context) {
super(context);
this.context = context;
}
@Override public void inflate(int menuRes, Menu menu) {
SherlockResourceLoader sherlockResourceLoader =
(SherlockResourceLoader) shadowOf(context.getApplicationContext()).getResourceLoader();
sherlockResourceLoader.inflateSherlockMenu(context, menuRes, menu);
}
}
// Copyright 2012 Square, Inc.
package com.squareup.test.actionbarsherlock;
import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuItem;
import com.actionbarsherlock.view.SubMenu;
import com.xtremelabs.robolectric.res.AttrResourceLoader;
import com.xtremelabs.robolectric.res.ResourceExtractor;
import com.xtremelabs.robolectric.res.XmlLoader;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import android.content.Context;
import android.text.TextUtils;
import com.xtremelabs.robolectric.tester.android.util.TestAttributeSet;
import com.xtremelabs.robolectric.util.I18nException;
/**
* Exact copy of the original {@link com.xtremelabs.robolectric.res.MenuLoader} provided by
* Robolectric, but instead uses the ABS {@link MenuItem} and the ABS {@link Menu}.
*/
public class SherlockMenuLoader extends XmlLoader {
private Map<String, MenuNode> menuNodesByMenuName = new HashMap<String, MenuNode>();
private AttrResourceLoader attrResourceLoader;
public SherlockMenuLoader(ResourceExtractor resourceExtractor,
AttrResourceLoader attrResourceLoader) {
super(resourceExtractor);
this.attrResourceLoader = attrResourceLoader;
}
@Override
protected void processResourceXml(File xmlFile, Document document, boolean ignored)
throws Exception {
MenuNode topLevelNode = new MenuNode("top-level", new HashMap<String, String>());
NodeList items = document.getChildNodes();
if (items.getLength() != 1) {
throw new RuntimeException(
"Expected only one top-level item in menu file " + xmlFile.getName());
}
if (items.item(0).getNodeName().compareTo("menu") != 0) {
throw new RuntimeException(
"Expected a top-level item called 'menu' in menu file " + xmlFile.getName());
}
processChildren(items.item(0).getChildNodes(), topLevelNode);
menuNodesByMenuName.put("menu/" + xmlFile.getName().replace(".xml", ""), topLevelNode);
}
private void processChildren(NodeList childNodes, MenuNode parent) {
for (int i = 0; i < childNodes.getLength(); i++) {
Node node = childNodes.item(i);
processNode(node, parent);
}
}
private void processNode(Node node, MenuNode parent) {
String name = node.getNodeName();
NamedNodeMap attributes = node.getAttributes();
Map<String, String> attrMap = new HashMap<String, String>();
if (attributes != null) {
int length = attributes.getLength();
for (int i = 0; i < length; i++) {
Node attr = attributes.item(i);
attrMap.put(attr.getNodeName(), attr.getNodeValue());
}
}
if (!name.startsWith("#")) {
MenuNode menuNode = new MenuNode(name, attrMap);
parent.addChild(menuNode);
NodeList children = node.getChildNodes();
if (children != null && children.getLength() != 0) {
for (int i = 0; i < children.getLength(); i++) {
Node nodei = children.item(i);
if (childToIgnore(nodei)) {
continue;
} else if (validChildren(nodei)) {
// recursively add all nodes
processNode(nodei, menuNode);
} else {
throw new RuntimeException("Unknown menu node" + nodei.getNodeName());
}
}
}
}
}
private static boolean childToIgnore(Node nodei) {
return TextUtils.isEmpty(nodei.getNodeName()) || nodei.getNodeName().startsWith("#");
}
private static boolean validChildren(Node nodei) {
return nodei.getNodeName().equals("item")
|| nodei.getNodeName().equals("menu")
|| nodei.getNodeName().equals("group");
}
public boolean inflateMenu(Context context, String key, Menu root) {
return inflateMenu(context, key, null, root);
}
public boolean inflateMenu(Context context, int resourceId, Menu root) {
return inflateMenu(context, resourceExtractor.getResourceName(resourceId), root);
}
private boolean inflateMenu(Context context, String key, Map<String, String> attributes,
Menu root) {
MenuNode menuNode = menuNodesByMenuName.get(key);
if (menuNode == null) return false;
try {
if (attributes != null) {
for (Map.Entry<String, String> entry : attributes.entrySet()) {
if (!entry.getKey().equals("menu")) {
menuNode.attributes.put(entry.getKey(), entry.getValue());
}
}
}
menuNode.inflate(context, root);
return true;
} catch (I18nException e) {
throw e;
} catch (Exception e) {
throw new RuntimeException("error inflating " + key, e);
}
}
public class MenuNode {
private String name;
private final TestAttributeSet attributes;
private List<MenuNode> children = new ArrayList<MenuNode>();
public MenuNode(String name, Map<String, String> attributes) {
this.name = name;
this.attributes =
new TestAttributeSet(attributes, resourceExtractor, attrResourceLoader, null, false);
}
public List<MenuNode> getChildren() {
return children;
}
public void addChild(MenuNode MenuNode) {
children.add(MenuNode);
}
private boolean isSubMenuItem(MenuNode child) {
//List<MenuLoader.MenuNode> ch = child.children;
//return ch != null && ch.size() == 1 && "menu".equals(ch.get(0).name);
// TODO Must fix to support sub menu items.
return false;
}
private void addChildrenInGroup(MenuNode source, int groupId, Menu root) {
for (MenuNode child : source.children) {
String name = child.name;
TestAttributeSet attributes = child.attributes;
if (strictI18n) {
attributes.validateStrictI18n();
}
if (name.equals("item")) {
if (isSubMenuItem(child)) {
SubMenu sub =
root.addSubMenu(groupId, attributes.getAttributeResourceValue("android", "id", 0),
0, attributes.getAttributeValue("android", "title"));
MenuNode subMenuNode = child.children.get(0);
addChildrenInGroup(subMenuNode, groupId, sub);
} else {
MenuItem menuItem =
root.add(groupId, attributes.getAttributeResourceValue("android", "id", 0), 0,
attributes.getAttributeValue("android", "title"));
}
} else if (name.equals("group")) {
int newGroupId = attributes.getAttributeResourceValue("android", "id", 0);
addChildrenInGroup(child, newGroupId, root);
}
}
}
public void inflate(Context context, Menu root) throws Exception {
addChildrenInGroup(this, 0, root);
}
}
}
// Copyright 2012 Square, Inc.
package com.squareup.test.actionbarsherlock;
import android.content.Context;
import com.actionbarsherlock.view.Menu;
import com.xtremelabs.robolectric.res.AttrResourceLoader;
import com.xtremelabs.robolectric.res.DocumentLoader;
import com.xtremelabs.robolectric.res.ResourceExtractor;
import com.xtremelabs.robolectric.res.ResourceLoader;
import java.io.File;
import java.io.FileFilter;
import java.util.List;
/**
* Custom resource loader for ActionBarSherlock. It extends the original {@link ResourceLoader}.
* At this time we just load all menus into a {@link SherlockMenuLoader}.
*/
public class SherlockResourceLoader extends ResourceLoader {
private SherlockMenuLoader sherlockMenuLoader;
public SherlockResourceLoader(int sdkVersion, Class rClass, List<File> resourcePath,
File assetsDir) throws Exception {
super(sdkVersion, rClass, resourcePath, assetsDir);
ResourceExtractor resourceExtractor = new ResourceExtractor();
try {
resourceExtractor.addLocalRClass(rClass);
resourceExtractor.addSystemRClass(android.R.class);
} catch (Exception e) {
throw new RuntimeException(e);
}
sherlockMenuLoader =
new SherlockMenuLoader(resourceExtractor, new AttrResourceLoader(resourceExtractor));
}
@Override protected void loadOtherResources(File resourceDir) {
DocumentLoader loader = new DocumentLoader(sherlockMenuLoader);
try {
loader.loadResourceXmlDirs(resourceDir.listFiles(new FileFilter() {
@Override public boolean accept(File file) {
return file.getPath().contains(File.separator + "menu");
}
}));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public void inflateSherlockMenu(Context context, int resource, Menu root) {
sherlockMenuLoader.inflateMenu(context, resource, root);
}
}
package com.squareup.test.actionbarsherlock;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.view.ContextMenu;
import android.view.View;
import com.actionbarsherlock.view.ActionProvider;
import com.actionbarsherlock.view.MenuItem;
import com.actionbarsherlock.view.SubMenu;
import com.xtremelabs.robolectric.Robolectric;
/**
* Copied from {@link com.xtremelabs.robolectric.tester.android.view.TestMenuItem}.
*/
public class TestSherlockMenuItem implements MenuItem {
private int itemId;
private CharSequence title;
private boolean enabled = true;
private OnMenuItemClickListener menuItemClickListener;
public int iconRes;
private Intent intent;
private SubMenu subMenu;
public TestSherlockMenuItem() {
super();
}
public TestSherlockMenuItem(int itemId) {
super();
this.itemId = itemId;
}
public void setItemId(int itemId) {
this.itemId = itemId;
}
@Override
public int getItemId() {
return itemId;
}
@Override
public int getGroupId() {
return 0;
}
@Override
public int getOrder() {
return 0;
}
@Override
public MenuItem setTitle(CharSequence title) {
this.title = title;
return this;
}
@Override
public MenuItem setTitle(int title) {
return null;
}
@Override
public CharSequence getTitle() {
return title;
}
@Override
public MenuItem setTitleCondensed(CharSequence title) {
return null;
}
@Override
public CharSequence getTitleCondensed() {
return null;
}
@Override
public MenuItem setIcon(Drawable icon) {
return null;
}
@Override
public MenuItem setIcon(int iconRes) {
this.iconRes = iconRes;
return this;
}
@Override
public Drawable getIcon() {
return null;
}
@Override
public MenuItem setIntent(Intent intent) {
this.intent = intent;
return this;
}
@Override
public Intent getIntent() {
return this.intent;
}
@Override
public MenuItem setShortcut(char numericChar, char alphaChar) {
return null;
}
@Override
public MenuItem setNumericShortcut(char numericChar) {
return null;
}
@Override
public char getNumericShortcut() {
return 0;
}
@Override
public MenuItem setAlphabeticShortcut(char alphaChar) {
return null;
}
@Override
public char getAlphabeticShortcut() {
return 0;
}
@Override
public MenuItem setCheckable(boolean checkable) {
return null;
}
@Override
public boolean isCheckable() {
return false;
}
@Override
public MenuItem setChecked(boolean checked) {
return null;
}
@Override
public boolean isChecked() {
return false;
}
@Override
public MenuItem setVisible(boolean visible) {
return null;
}
@Override
public boolean isVisible() {
return false;
}
@Override
public MenuItem setEnabled(boolean enabled) {
this.enabled = enabled;
return this;
}
@Override
public boolean isEnabled() {
return enabled;
}
@Override
public boolean hasSubMenu() {
return subMenu != null;
}
@Override
public SubMenu getSubMenu() {
return subMenu;
}
public void setSubMenu(SubMenu subMenu) {
this.subMenu = subMenu;
}
@Override
public MenuItem setOnMenuItemClickListener(OnMenuItemClickListener menuItemClickListener) {
this.menuItemClickListener = menuItemClickListener;
return this;
}
@Override
public ContextMenu.ContextMenuInfo getMenuInfo() {
return null;
}
@Override
public void setShowAsAction(int i) {
}
@Override
public MenuItem setShowAsActionFlags(int i) {
return null;
}
@Override
public MenuItem setActionView(View view) {
return null;
}
@Override
public MenuItem setActionView(int i) {
return null;
}
@Override
public View getActionView() {
return null;
}
@Override
public MenuItem setActionProvider(ActionProvider actionProvider) {
return null;
}
@Override
public ActionProvider getActionProvider() {
return null;
}
@Override
public boolean expandActionView() {
return false;
}
@Override
public boolean collapseActionView() {
return false;
}
@Override
public boolean isActionViewExpanded() {
return false;
}
@Override
public MenuItem setOnActionExpandListener(OnActionExpandListener onActionExpandListener) {
return null;
}
public void click() {
if (enabled && menuItemClickListener != null) {
menuItemClickListener.onMenuItemClick(this);
} else if (enabled && intent != null) {
Robolectric.application.startActivity(intent);
}
}
}
@colabug
Copy link

colabug commented Dec 5, 2012

Thanks for putting this together! I've been banging my head against a wall for some time trying to get maven, robolectric, actionbar sherlock, and intellij, to all play nicely. I've given up on building with intellij for now and am focusing on maven.

I have an app with an action bar when I skip the tests in the maven build. (The IntelliJ build fails on ManifestParsingTest complaining that it doesn't know where junit is).

I copied your files above into src/test/java/com/blah/blah/support/ (except ShadowSherlockFragmentActivity.java which lives in src/test/java/com/blah/blah/support/shadows/) and put this line in the constructor for my custom test runner (lives in support folder):

ActionBarSherlock.registerImplementation(ActionBarSherlockRobolectric.class);

I'm running into these build errors (IntelliJ also has red squigglies for the same stuff):

[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.0:testCompile (default-testCompile) on project Blah: Compilation failure: Compilation failure:
[ERROR] /Users/clatislaw/Documents/Code/Android/projectName/src/test/java/com/blah/blah/support/SherlockResourceLoader.java:[29,9] cannot find symbol
[ERROR] symbol  : constructor ResourceLoader(int,java.lang.Class,java.util.List<java.io.File>,java.io.File)
[ERROR] location: class com.xtremelabs.robolectric.res.ResourceLoader
[ERROR] /Users/clatislaw/Documents/Code/Android/projectName/src/test/java/com/blah/blah/support/SherlockResourceLoader.java:[45,5] method does not override or implement a method from a supertype
[ERROR] /Users/clatislaw/Documents/Code/Android/projectName/src/test/java/com/blah/blah/support/ActionBarSherlockTestRunner.java:[39,37] resourceLoaderForRootAndDirectory has private access in com.xtremelabs.robolectric.RobolectricTestRunner
[ERROR] /Users/clatislaw/Documents/Code/Android/projectName/src/test/java/com/blah/blah/support/ActionBarSherlockTestRunner.java:[47,30] cannot find symbol
[ERROR] symbol  : method getResourcePath()
[ERROR] location: class com.xtremelabs.robolectric.RobolectricConfig
[ERROR] /Users/clatislaw/Documents/Code/Android/projectName/src/test/java/com/blah/blah/support/ActionBarSherlockTestRunner.java:[48,9] resourceLoaderForRootAndDirectory has private access in com.xtremelabs.robolectric.RobolectricTestRunner
[ERROR] /Users/clatislaw/Documents/Code/Android/projectName/src/test/java/com/blah/blah/support/ActionBarSherlockTestRunner.java:[38,3] method does not override or implement a method from a supertype

Here's my pom:

<?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.blah.blah</groupId>
    <artifactId>projectName</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <packaging>apk</packaging>
    <name>Project Name App</name>

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

        <dependency>
            <groupId>com.pivotallabs</groupId>
            <artifactId>robolectric</artifactId>
            <version>1.1</version>
            <scope>test</scope>
        </dependency>

        <dependency>
             <groupId>junit</groupId>
             <artifactId>junit</artifactId>
             <version>4.8.2</version>
             <scope>test</scope>
        </dependency>

        <dependency>
             <groupId>com.google.android</groupId>
             <artifactId>support-v4</artifactId>
             <version>r6</version>
        </dependency>

        <dependency>
            <groupId>com.actionbarsherlock</groupId>
            <artifactId>library</artifactId>
            <version>4.1.0</version>
            <type>apklib</type>
        </dependency>
    <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>android-maven-plugin</artifactId>
                <version>3.2.0</version>
                <configuration>
                    <sdk>
                        <platform>15</platform>
                    </sdk>
                </configuration>
                <extensions>true</extensions>
            </plugin>
        </plugins>
    </build>
</project>

Is there some project config I'm missing?

P.S. Also added a question to stack overflow: http://stackoverflow.com/questions/13728310/how-do-you-integrate-robolectric-maven-actionbarsherlock-and-preferably-int

@duncandee
Copy link

Jake it seems like square has removed the repo "https://github.com/square/robolectric/commit/fac24e5ef6d5830e6e67ad27aff2f8f57cedb5a1"

Getting a error calling super in SherlockResourceLoader, and resourceLoaderForRootAndDirectory is not visible.

@levibostian
Copy link

Exactly what version of Robolectric is this using? I am trying 1.2-with-dependencies and I am getting same error as @duncandee

EDIT:
Not sure what version this is using or how to get it working, but I ended up getting v2.1 to work with a combination of this and xian's fork. Gist here.

@javierLiarte
Copy link

Thanks Jake, @leviboostian and xian ;)

Although your gist is no longer accesible I think I've finally got this working. I'm using xian's fork gist with robolectric v2.1 (tested and working also with 2.1.1; in 2.2 I'm getting NPE) and ABS 4.3.1.

I've had to change Implementation import in SherlockMenuInflater that is what I suppose you did:

//import org.robolectric.internal.Implementation;
import org.robolectric.annotation.Implementation;

@tokunbo
Copy link

tokunbo commented Oct 9, 2013

Can anyone get this to work with ABS4.4.0 & robolectric-2.1.1.jar? What do you guys have for @RunWith()? I've tried all I can think of, but I just keep getting errors.

Caused by: java.lang.RuntimeException: Couldn't find content container view
at com.actionbarsherlock.internal.ActionBarSherlockCompat.generateLayout(ActionBarSherlockCompat.java:1015)
at com.actionbarsherlock.internal.ActionBarSherlockCompat.installDecor(ActionBarSherlockCompat.java:902)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment