2016-02-17 13 views
5

Próbuję użyć PowerMocka do wyśmiewania klasy metodą statyczną, ale w szczególności chcę to zrobić w ciągu Test oprzyrządowania Android. Aby było jasne, chcę przeprowadzić test na prawdziwym urządzeniu z Androidem lub emulatorze. Korzystam z Android Studio (1.5.1) i Gradle (1.5.0). Aby uniknąć czerwonych śledzi, stworzyłem naprawdę prostą i raczej prymitywną aplikację "cześć świat". Ta aplikacja pokazuje po prostu 2 fragmenty tekstu, jeden pobrany ze statycznej metody i jeden z niestatycznej metody. Napisałem testy instrumentacyjne dla obu tych klas "dostawców tekstu". Można zobaczyć tę aplikację tutaj:Używanie PowerMock i Mockito w teście Instrumentacji Android - Błąd - Powielanie plików - org.mockito.plugins.MockMaker

https://github.com/Kai2k/PowerMockAndroidTest.git

Kiedy próbuje uruchomić testy oprzyrządowania pojawia się błąd, który to wydaje wielu ludzi stara się osiągnąć ten otrzymujemy:

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 

Moje współzależności na mojej aplikacji build.gradle plik wyglądać następująco:

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' 
} 

można zauważyć pewne zależności „testCompile” na mock zasilania i dotyczą d bibliotek (oprócz androidTestCompile). Wynika to z tego, że w przypadku pasa i szelek chciałbym sprawdzić, czy uda mi się również wykonać test łączący (bez narzędzi) (który wykorzystuje siłę próbną). Udało mi się to osiągnąć, ale nie test oprzyrządowania. Oto moje (straszne) Kod:

Główna działalność:

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); 
} 
} 

plików układu:

<?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> 

I klasy, aby uzyskać statyczne i nie statyczne wartości:

package com.example.android.powermocktest; 

public class GetStaticValue { 

private final static String THE_VALUE = "Hi, I'm static"; 

public static String getTheStaticValue(){ 
    return THE_VALUE; 
} 
} 

package com.example.android.powermocktest; 

public class GetNonStaticValue { 

public String getNonStaticString(){ 
    return "Hi, I'm non-static"; 
} 
} 

I wreszcie klasy testowe. Pierwsze testy oprzyrządowania:

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")); 
    } 
} 

a teraz testy JUnit (pracujące):

package com.example.android.powermocktest; 

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

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

@RunWith(PowerMockRunner.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")); 
    } 
} 

Co próbowałem dotąd:

Zrobiłem trochę czytania tego problemu i jedno rozwiązanie, które znalazłem, czego nie próbowałem, to ręcznie złamać słoiki biblioteki i udowodnić, że są szkodliwe duplikaty. Jako (w pracy) używamy gradle i nie pracujemy z lokalnymi słoikami, których wolałbym nie robić.

How to get Powermock to work with Dexmaker

Słyszałem, że ludzie sugerują, używając „wyklucza” w Android części Gradle pliku kompilacji. To nie jest odpowiednie, ponieważ do testu oprzyrządowania jest ono uruchamiane (przez Android Studio/Gradle) jako apk i uruchamiane na urządzeniu. Jako takie, słoiki z próbnymi mocami są potrzebne do przeprowadzenia testów.

android studio: gradle dependency error

Próbowałem usuwając niektóre z zależnościami, które widzisz wymienionych w moim pliku kompilacji powyżej. Próbowałem na przykład usunąć zależność "org.powermock: powermock-api-mockito", ale na przykład trzeba użyć "mockStatic".

Wydaje się, że ktoś był udany przy użyciu Maven, mówiąc Maven wykluczyć duplikaty:

https://groups.google.com/forum/#!searchin/powermock/android/powermock/ndZ2ZliYGCY/Eh226605u2cJ

PowerMock + Mockito + Maven on Android app showing Dex loader error

Próbowałem sprawdzić, czy istnieje sposób, aby opowiadać Gradle zignoruj ​​zduplikowane klasy w słoikach zależności, ale jak dotąd nie udało mi się.

Uważam, że warto poszukać, po pierwsze, moc makiety może być bardzo przydatna, gdy używana oszczędnie, a po drugie, nie mogę uwierzyć, że ta kwestia nie została rozwiązana (na pewno napotkano ją wcześniej!).

Jako ostatni punkt, ja zauważyłem, że Google sami zdają się sugerować, że z natury szyderczy jest tylko dla jednostki, a nie testów oprzyrządowania:

http://developer.android.com/training/testing/start/index.html

Każda pomoc ktoś może zaoferować byłoby bardzo mile widziane. Dzięki.

+0

Czy byłeś w stanie rozwiązać ten problem? – thedarkpassenger

+0

Nie, jeszcze nie, ten problem jest wciąż nierozstrzygnięty. – Kai

Odpowiedz

0

Czy masz to w swoim projekcie/module gradle?

packagingOptions { 
    exclude 'fileNameYouWantToExclude' 
} 

W ten sposób Androd wprowadzi tylko jeden plik, jeżeli znajdują się duplikaty

+0

Mój problem to zduplikowane klasy w obrębie kilku słoików. Potrzebuję innych klas w wymienionych słoikach, więc usunięcie (lub wykluczenie) całego słoika nie jest możliwe. Obecnie wygląda na to, że rozwiązaniem będzie wiele hakowania słoików, co nie jest realnym rozwiązaniem. Chyba, że ​​ktoś zna sposób na wskazanie klasy, aby zignorować powielające się klasy? – Kai

2

udało mi się rozwiązać ten problem z następujących czynności. Jeśli zobaczysz komunikat o błędzie Powielone pliki skopiowane w pliku APK [nazwa pliku], dodaj, że [nazwa pliku] zostanie wykluczona w opakowaniuOpcje.

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

Użyłem powyższego wykluczenia, a teraz nie znaleziono żadnego testu. –

+0

Powoduje to błąd podczas ładowania moich testów, nie działa dla mnie – Miquel

Powiązane problemy