Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/229.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 在Android工具测试中使用PowerMock和Mockito-错误-重复文件-org.Mockito.plugins.MockMaker_Java_Android_Gradle_Mockito_Powermock - Fatal编程技术网

Java 在Android工具测试中使用PowerMock和Mockito-错误-重复文件-org.Mockito.plugins.MockMaker

Java 在Android工具测试中使用PowerMock和Mockito-错误-重复文件-org.Mockito.plugins.MockMaker,java,android,gradle,mockito,powermock,Java,Android,Gradle,Mockito,Powermock,我试图使用PowerMock用静态方法模拟一个类,但我特别希望在Android工具测试中这样做。为了清楚起见,我希望在真正的Android设备或模拟器上运行测试。 我正在使用Android Studio(1.5.1)和Gradle(1.5.0)。为了避免任何麻烦,我创建了一个非常基本、相当粗糙的“hello world”应用程序。这个应用程序只显示两段文本,一段是从静态方法检索的,另一段是从非静态方法检索的。我已经为这两个“文本提供程序”类编写了插装测试。您可以在此处看到此应用程序: 当尝试运

我试图使用PowerMock用静态方法模拟一个类,但我特别希望在Android工具测试中这样做。为了清楚起见,我希望在真正的Android设备或模拟器上运行测试。 我正在使用Android Studio(1.5.1)和Gradle(1.5.0)。为了避免任何麻烦,我创建了一个非常基本、相当粗糙的“hello world”应用程序。这个应用程序只显示两段文本,一段是从静态方法检索的,另一段是从非静态方法检索的。我已经为这两个“文本提供程序”类编写了插装测试。您可以在此处看到此应用程序:

当尝试运行检测测试时,我得到一个错误,许多人试图实现这个错误:

com.android.build.api.transform.TransformException: com.android.builder.packaging.DuplicateFileException: Duplicate files copied in APK mockito-extensions/org.mockito.plugins.MockMaker
File1: /Users/kaiarmer/.gradle/caches/modules-2/files-2.1/com.crittercism.dexmaker/dexmaker-mockito/1.4/70892a94894462c1b35df3c8a77d21b7e843550b/dexmaker-mockito-1.4.jar
File2: /Users/kaiarmer/.gradle/caches/modules-2/files-2.1/org.powermock/powermock-api-mockito/1.6.4/fe12509b7e9e49d25131f4155145748a31e42e40/powermock-api-mockito-1.6.4.jar
我对应用程序的build.gradle文件的依赖项如下所示:

dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
testCompile 'junit:junit:4.12'
testCompile 'org.powermock:powermock-api-mockito:1.6.4'
testCompile 'org.powermock:powermock-module-junit4-rule-agent:1.6.4'
testCompile 'org.powermock:powermock-module-junit4-rule:1.6.4'
testCompile 'org.powermock:powermock-module-junit4:1.6.4'

androidTestCompile 'org.mockito:mockito-core:1.10.19'
androidTestCompile 'org.powermock:powermock-api-mockito:1.6.4'
androidTestCompile 'com.android.support:support-annotations:23.1.1'
androidTestCompile 'com.android.support.test:runner:0.4.1'
androidTestCompile 'com.android.support.test:rules:0.4.1'
androidTestCompile 'org.hamcrest:hamcrest-library:1.3'
androidTestCompile 'com.crittercism.dexmaker:dexmaker:1.4'
androidTestCompile 'com.crittercism.dexmaker:dexmaker-mockito:1.4'

compile 'com.android.support:appcompat-v7:23.1.1'
compile 'com.android.support:design:23.1.1'
}
您将注意到一些对power mock和相关库的“testCompile”依赖性(除了androidTestCompile)。这是因为对于腰带和背带,我想看看是否可以让junit(非仪器化)测试(使用power mock)也正常工作。我能够做到这一点,但没有仪器测试。这是我的(可怕的)代码:

主要活动:

package com.example.android.powermocktest;

import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);

    FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
    fab.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                    .setAction("Action", null).show();
        }
    });

    TextView textView1 = (TextView)findViewById(R.id.textView1);
    textView1.setText(GetStaticValue.getTheStaticValue());

    TextView textView2 = (TextView)findViewById(R.id.textView2);
    textView2.setText(new GetNonStaticValue().getNonStaticString());
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.menu_main, menu);
    return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Handle action bar item clicks here. The action bar will
    // automatically handle clicks on the Home/Up button, so long
    // as you specify a parent activity in AndroidManifest.xml.
    int id = item.getItemId();

    //noinspection SimplifiableIfStatement
    if (id == R.id.action_settings) {
        return true;
    }

    return super.onOptionsItemSelected(item);
}
}
布局文件:

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout         xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context="com.example.android.powermocktest.MainActivity">

<android.support.design.widget.AppBarLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:theme="@style/AppTheme.AppBarOverlay">

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="?attr/colorPrimary"
        app:popupTheme="@style/AppTheme.PopupOverlay" />

</android.support.design.widget.AppBarLayout>

<include layout="@layout/content_main" />

<android.support.design.widget.FloatingActionButton
    android:id="@+id/fab"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="bottom|end"
    android:layout_margin="@dimen/fab_margin"
    android:src="@android:drawable/ic_dialog_email" />

</android.support.design.widget.CoordinatorLayout>

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:context="com.example.android.powermocktest.MainActivity"
tools:showIn="@layout/activity_main">

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/textView1"
    android:text="Hello World!" />
<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_below="@+id/textView1"
    android:id="@+id/textView2"
    android:text="Hello World again!" />
</RelativeLayout>
最后是测试类。首先,仪器测试:

package com.example.android.powermocktest;

import android.support.test.runner.AndroidJUnit4;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;

import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.powermock.api.mockito.PowerMockito.when;

@RunWith(AndroidJUnit4.class)
@PrepareForTest(GetStaticValue.class)
public class GetStaticValueTest {

    @Test
    public void getStaticValueReturnsValue(){
        PowerMockito.mockStatic(GetStaticValue.class);
        when(GetStaticValue.getTheStaticValue()).thenReturn("Hi, I'm static");
        assertThat(GetStaticValue.getTheStaticValue(), equalTo("Hi, I'm static"));
    }
}

package com.example.android.powermocktest;

import android.support.test.runner.AndroidJUnit4;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;

import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.mockito.Mockito.when;

@RunWith(AndroidJUnit4.class)
public class GetNonStaticValueTest {

    @Test
    public void getNonStaticValueReturnsNonStaticValue(){
        GetNonStaticValue getNonStaticValue = Mockito.mock(GetNonStaticValue.class);
        when(getNonStaticValue.getNonStaticString()).thenReturn("Hi, I'm non-static");
        assertThat(getNonStaticValue.getNonStaticString(), equalTo("Hi, I'm non-static"));
    }
}
现在是jUnit测试(有效):

到目前为止,我所尝试的:

我已经读了一些关于这个问题的书,找到了一个解决方案,我没有尝试过,那就是手动打开powermock库jar并删除有问题的复制类。因为(在工作中)我们使用gradle,不使用本地罐子,所以我不希望这样做

我听说有人建议在gradle构建文件的Android部分中使用“排除”。这不适用于运行的仪器测试,因为它是(由Android Studio/Gradle)作为apk构建并在设备上启动的。因此,运行测试需要电源模拟jar

我已尝试删除上面我的构建文件中列出的一些依赖项。例如,我尝试删除“org.powermock:powermock api mockito”依赖项,但需要使用“mockStatic”作为示例

似乎有人成功地使用了Maven,告诉Maven排除重复项:

我试着看看是否有办法告诉Gradle忽略依赖项jar中的重复类,但到目前为止我没有成功

我觉得这是值得追求的,因为首先,权力模拟可以非常有用时,节约使用,其次,我不能相信,这个问题还没有得到解决(这肯定是以前遇到过!)

最后一点,我确实注意到谷歌本身似乎天生就认为模拟只用于单元测试,而不是仪器测试:

package com.example.android.powermocktest;

import android.support.test.runner.AndroidJUnit4;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;

import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.powermock.api.mockito.PowerMockito.when;

@RunWith(AndroidJUnit4.class)
@PrepareForTest(GetStaticValue.class)
public class GetStaticValueTest {

    @Test
    public void getStaticValueReturnsValue(){
        PowerMockito.mockStatic(GetStaticValue.class);
        when(GetStaticValue.getTheStaticValue()).thenReturn("Hi, I'm static");
        assertThat(GetStaticValue.getTheStaticValue(), equalTo("Hi, I'm static"));
    }
}

package com.example.android.powermocktest;

import android.support.test.runner.AndroidJUnit4;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;

import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.mockito.Mockito.when;

@RunWith(AndroidJUnit4.class)
public class GetNonStaticValueTest {

    @Test
    public void getNonStaticValueReturnsNonStaticValue(){
        GetNonStaticValue getNonStaticValue = Mockito.mock(GetNonStaticValue.class);
        when(getNonStaticValue.getNonStaticString()).thenReturn("Hi, I'm non-static");
        assertThat(getNonStaticValue.getNonStaticString(), equalTo("Hi, I'm non-static"));
    }
}


任何人能提供的任何帮助都将不胜感激。谢谢。

你的项目/模块中有这个吗

packagingOptions {
    exclude 'fileNameYouWantToExclude'
}

通过这种方式,如果发现重复的文件,Androd将只放置一个文件

我可以通过以下方法解决这个问题。如果您看到任何显示在APK[filename]中复制了重复文件的错误消息,请在PackageOptions中添加要排除的[filename]

android {
    packagingOptions {
        exclude 'mockito-extensions/org.mockito.plugins.MockMaker'
    }
}

唯一正确的答案是PowerMockito不支持Android使用的Davik VM,它是针对标准JVM的。因此,您不能将其用于指令化测试,只能用于单元测试。

您能够解决此问题吗?不,还没有,此问题仍然存在。看起来此问题将部分消失-我的问题是多个jar中的重复类。我需要上述jar中的其他类,因此不可能删除(或排除)整个jar。目前看来,解决方案将是大量的jar黑客攻击,这不是一个可行的解决方案。除非有人知道告诉grade忽略重复类的方法?我使用了上面的exclude,现在找不到任何测试。这会导致加载我的测试时出错,对methis不起作用。这可能会修复插入指令的测试的问题,但会导致使用PowerMockito/Mockito的单元测试现在不起作用。perriod还说,我也看到了我的答案,我认为没有任何解决方案,因为PowerMockito不适用于Android检测测试。
android {
    packagingOptions {
        exclude 'mockito-extensions/org.mockito.plugins.MockMaker'
    }
}