Android在模块/库

时间:2015-12-24 18:37:07

标签: java android dex android-espresso

伸出援助之手,因为我一直在以前从未见过的问题撞墙。

我有一个标准的片段活动,使用浓缩咖啡进行测试。我在应用程序链接的关联模块库中有一个静态管理器。

问题:

当测试运行时,它会对我的ServiceManager进行静态调用。当代码在onCreateView中执行时,在堆栈跟踪中,它在管理器中调用一个不同的方法,而不是它应该的方法。更奇怪的是,传递的参数在追踪时毫无意义。代码如下(简化项目以说明正在发生的事情)。

ServiceManager.java - 来自项目库

public class ServiceManager {
  private static final ServiceManager INSTANCE = new ServiceManager();

  private UserManager userManager;

  public static initForTest(Context context) {
    // some storage initialization here
    INSTANCE.userManager = new UserManagerImpl();
  }

  public static ServiceManager getInstance() {
    return INSTANCE;
  }

  public static UserManager getUserManager() {
    return INSTANCE.userManager;
  }
}

UserManager.java - 来自项目库

public interface UserManager {
  void registerListener(UserListener listener);

  void refreshDataFromSource(String id);
}

UserManagerImpl.java - 来自项目库

public class UserManagerImpl implements UserManager {
  public void registerListener(UserListener listener) {
    // code really does not matter here, but I have a listener manager
    ManagerListeners.register(UserListener.class, this);
  }

  public void refreshDataFromSource(String id) {
    // kicks off an async task of mine
    Log.i(TAG, "initiating refresh for %s", id);

    UserRefreshTask task = new UserRefreshTask(
        new TaskCallbackWithReturn<Consumer>() {
          @Override
          public void done(Consumer consumer) {
            refreshAllListeners(true);
        }

        @Override
        public void fail() {
          refreshAllListeners(false);
        }
      }, id);

      task.execute();
  }
}

NewUserStartFragment.java - 在应用项目中

public class UserProfileStartFragment extends Fragment implements UserListener {

  @Override
  public View onCreateView(LayoutInflater inflater, ViewGroup container,
                       Bundle savedInstanceState) {
    // Get the view from fragment_newuserstart.xml
    View view = inflater.inflate(R.layout.fragment_newuserstart, container, false);

    // register listeners
     ServiceManager.getInstance().getUserManager().registerListener(this);

    // rest does not matter since we don't get to it.
    return view;
  }
}

来自应用项目的支持(死简单)活动 NewUserActivity.java

public class NewUserActivity extends FragmentActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setContentView(R.layout.activity_newuser);

    if (savedInstanceState == null) {
      FragmentUtils.replace(this, R.id.fragment_userscreen, new UserProfileStartFragment());
    }

    Log.i(TAG, "Activity created");
  }
}

一个简单的测试 NewUserStartFragmentTest.java - 在app项目中测试

@RunWith(AndroidJUnit4.class)
public class UserProfileStartFragmentTest {
  // on activity rule, activity initialization delayed on false
  @Rule
  public ActivityTestRule<NewUserActivity> mActivityRule =
      new ActivityTestRule<>(NewUserActivity.class, true, false);

  private NewUserActivity userActivity;

  @Before
  public void setUp() throws Exception {
    Instrumentation instrumentation
        = InstrumentationRegistry.getInstrumentation();
    Context context = instrumentation.getTargetContext();

    // service manager at this point will be initialized
    ServiceManager.initForTest(context);
  }

  @After
  public void tearDown() throws Exception {
    // ensure activity is dead
    ActivityUtils.finish(userActivity);

    ServiceManager.reset();
  }

  @Test
  public void testInitialScreen() throws Exception {
    userActivity = mActivityRule.launchActivity(new Intent());

    onView(withId(R.id.image_profile_photo)).check(matches(notNullValue()));
    onView(withId(R.id.button_email)).check(matches(notNullValue()));
    onView(withId(R.id.button_existing)).check(matches(notNullValue()));
    onView(withId(R.id.button_cancel)).check(matches(notNullValue()));
  }
}

现在好奇

测试运行时,它总是报告以下内容。

java.lang.IllegalArgumentException: consumerId must not be null or empty
at com.google.common.base.Preconditions.checkArgument(Preconditions.java:122)
at com.arryved.android.applibrary.tasks.UserRefreshTask.<init>(UserRefreshTask.java:31)
**at com.arryved.android.applibrary.manager.usermanager.UserManagerImpl.refreshDataFromSource(UserManagerImpl.java:300)
at com.arryved.emptor.fragments.UserProfileStartFragment.onCreateView(UserProfileStartFragment.java:41)**
at android.support.v4.app.Fragment.performCreateView(Fragment.java:1965)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1078)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1259)
at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:738)
at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1624)
at android.support.v4.app.FragmentController.execPendingActions(FragmentController.java:330)
at android.support.v4.app.FragmentActivity.onStart(FragmentActivity.java:547)
at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1220)
at android.support.test.runner.MonitoringInstrumentation.callActivityOnStart(MonitoringInstrumentation.java:546)
at android.app.Activity.performStart(Activity.java:5953)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2261)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2360)
at android.app.ActivityThread.access$800(ActivityThread.java:144)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1278)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5221)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)

UM,它不应该执行refreshDataFromSource。它应该执行registerListener。

因此,我决定添加一个停止点并进行调试。更奇怪的是,它正在执行代码,但不传递字符串,而是将片段作为参数传递。单独使用Java变量应该会导致失败!这告诉我它必须是一个字节代码混淆。它是dex吗?还有别的吗?我以前从未见过这样的事。

我曾尝试过MacOs android studio和Linux android studio。我已经完成了从命令行和工作室清理的构建。我遇到过几种不同的仿真器和一台实际的Nexus 5设备。没关系,相同的结果告诉我在构建之后它会混淆,而不是因为代码。

哦,还有另一个参考点。只需运行应用程序,片段就可以正常工作。当我刚刚运行测试时,这似乎正在发生。 (但我担心在dex中还有其他一些险恶的东西,所以我不相信应用程序,除非我在测试中弄明白这一点。)

以下是该应用的 build.gradle

apply plugin: 'com.android.application'

apply plugin: 'com.google.gms.google-services'

android {
  compileSdkVersion 23
  buildToolsVersion "23.0.1"

  defaultConfig {
      applicationId "com.arryved.emptor"
      minSdkVersion 19
      targetSdkVersion 23
      versionCode 1
      versionName "1.0"
      testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"

      // Enabling multidex support.
      multiDexEnabled true
    }
    buildTypes {
      release {
        minifyEnabled false
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    }
  }

  packagingOptions {
      exclude 'META-INF/LICENSE.txt'
      exclude 'META-INF/maven/com.google.guava/guava/pom.properties'
      exclude 'META-INF/maven/com.google.guava/guava/pom.xml'
  }

  dexOptions {
      javaMaxHeapSize "4g"
  }
}

dependencies {
  compile fileTree(dir: 'libs', include: ['*.jar'])

  compile 'com.android.support:appcompat-v7:23.1.0'
  compile 'com.android.support:recyclerview-v7:23.1.0'

  androidTestCompile 'com.android.support.test:runner:0.4'
  androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.1') {
    exclude group: 'com.google.guava', module: 'guava'
  }
  // add this for intent mocking support
  androidTestCompile('com.android.support.test.espresso:espresso-intents:2.2') {
    exclude group: 'com.google.guava', module: 'guava'
  }
  // add this for webview testing support
  androidTestCompile('com.android.support.test.espresso:espresso-web:2.2.1') {
    exclude group: 'com.google.guava', module: 'guava'
  }

  compile project(':AppLibrary')
}

我的 AppLibrary build.gradle

apply plugin: 'com.android.library'

buildscript {
  repositories {
    mavenCentral()
  }

  dependencies {
    classpath 'com.android.tools.build:gradle:1.5.0'
  }
}

android {
  compileSdkVersion 23
  buildToolsVersion "23.0.1"

  defaultConfig {
    minSdkVersion 19
    targetSdkVersion 23
    versionCode 1
    versionName "1.0"
    testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"

    // Enabling multidex support.
    multiDexEnabled true
  }
  buildTypes {
    release {
        minifyEnabled false
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    }
  }

  packagingOptions {
      exclude 'META-INF/LICENSE.txt'
  }

  dexOptions {
      javaMaxHeapSize "4g"
  }
}

dependencies {
  compile fileTree(dir: 'libs', include: ['*.jar'])
  compile 'com.android.support:multidex:1.0.0'
  compile("com.google.android.gms:play-services:8.3.0") {
    exclude group: 'com.android.support', module: 'support-v4'
  }

  compile 'com.android.support:appcompat-v7:23.1.0'
  compile 'com.android.support:recyclerview-v7:23.1.0'

  androidTestCompile 'com.android.support.test:runner:0.4'
  androidTestCompile 'com.android.support.test:rules:0.4'
}

-------------- UPDATE ---------------

只是看看会发生什么,我更新了服务管理器来处理硬实现(UserManagerImpl)而不是接口(UserManager)。使用实现而不是接口引用时,测试通过。因此,在这一点上,我能确定的最好的是,在链接周期中,android或dex对界面感到困惑。当我将其更改回来时,测试又恢复为失败,如上所示(因此也不是随机构建问题)。

0 个答案:

没有答案