web-dev-qa-db-fra.com

Besoin d'aide pour écrire un test unitaire avec Mockito et JUnit4

Besoin d'aide pour écrire un test unitaire pour le code ci-dessous en utilisant Mockito et JUnit4,

public class MyFragmentPresenterImpl { 
      public Boolean isValid(String value) {
        return !(TextUtils.isEmpty(value));
      }
}

J'ai essayé la méthode ci-dessous: MyFragmentPresenter mMyFragmentPresenter

@Before
public void setup(){
    mMyFragmentPresenter=new MyFragmentPresenterImpl();
}

@Test
public void testEmptyValue() throws Exception {
    String value=null;
    assertFalse(mMyFragmentPresenter.isValid(value));
}

mais il retourne après exception,

Java.lang.RuntimeException: méthode isEmpty in Android.text.TextUtils pas moqué. Voir http://g.co/androidstudio/not-mocked pour plus de détails. à Android.text.TextUtils.isEmpty (TextUtils.Java) sur ....

20
Kadari

Comme la classe JUnit TestCase ne peut pas utiliser les API liées à Android, nous devons la simuler.
Utilisez PowerMockito pour simuler la classe statique.

Ajoutez deux lignes au-dessus de votre classe de cas de test,

@RunWith(PowerMockRunner.class)
@PrepareForTest(TextUtils.class)
public class YourTest
{

}

Et le code d'installation

@Before
public void setup() {
    PowerMockito.mockStatic(TextUtils.class);
    PowerMockito.when(TextUtils.isEmpty(any(CharSequence.class))).thenAnswer(new Answer<Boolean>() {
        @Override
        public Boolean answer(InvocationOnMock invocation) throws Throwable {
            CharSequence a = (CharSequence) invocation.getArguments()[0];
            return !(a != null && a.length() > 0);
        }
    });
}

Cela implémente TextUtils.isEmpty() avec notre propre logique.

Ajoutez également des dépendances dans les fichiers app.gradle.

testCompile "org.powermock:powermock-module-junit4:1.6.2"
testCompile "org.powermock:powermock-module-junit4-rule:1.6.2"
testCompile "org.powermock:powermock-api-mockito:1.6.2"
testCompile "org.powermock:powermock-classloading-xstream:1.6.2"

Merci Behelit's et Exception's answer.

35
Johnny

Utilisez PowerMockito

Ajoutez ceci au-dessus de votre nom de classe et incluez tous les autres noms de classes CUT (classes testées)

@RunWith(PowerMockRunner.class)
@PrepareForTest({TextUtils.class})
public class ContactUtilsTest
{

Ajoutez ceci à votre @Before

@Before
public void setup(){
    PowerMockito.mockStatic(TextUtils.class);
    mMyFragmentPresenter=new MyFragmentPresenterImpl();
}

Cela obligera PowerMockito à renvoyer les valeurs par défaut pour les méthodes de TextUtils

Vous devez également ajouter les dépendances correspondantes.

testCompile "org.powermock:powermock-module-junit4:1.6.2"
testCompile "org.powermock:powermock-module-junit4-rule:1.6.2"
testCompile "org.powermock:powermock-api-mockito:1.6.2"
testCompile "org.powermock:powermock-classloading-xstream:1.6.2"
6
behelit

Ceci est un problème connu comme mentionné par @Exception. Dans mon cas, je suis également tombé sur la même situation, mais sur les conseils du développeur principal, j'ai décidé d'utiliser Strings.isNullOrEmpty() au lieu de TextUtils.isEmpty(). Il s’est avéré être un bon moyen de l’éviter. 

Mise à jour: je ferais mieux de mentionner que cette fonction utilitaire Strings.isNullOrEmpty() requiert la bibliothèque Guava.

6
Wahib Ul Haq

Ceci est un problème connu, dû à une clause dans Testing Fundamental of Android qui dit:

Vous pouvez utiliser la classe JUnit TestCase pour effectuer des tests unitaires sur une classe cela n'appelle pas les API Android.

Le comportement par défaut est problématique lors de l'utilisation de classes telles que Log ou TextUtils.

Pour résumer:

  1. Android.jar est fictif avant, donc certaines valeurs de retour d'API Android peuvent ne pas être comme prévu.
  2. JUnit lui-même est une mesure unique pour le code Java. Essayez donc de ne pas utiliser les méthodes de l'API Android.

Source:http://www.liangfeizc.com/2016/01/28/unit-test-on-Android/

3
Exception

ajoutez cette ligne dans votre fichier Gradle dans le cas d'Android Studio.

Android{
....
 testOptions {
        unitTests.returnDefaultValues = true
 }
}
3
Abhishek

J'ai pu résoudre cette erreur en exécutant la classe de test avec les éléments suivants.

@RunWith (RobolectricGradleTestRunner.class) Public class MySimpleTest {..... un tas de tests }

Cette page de wiki explique plus en détail https://github.com/yahoo/squidb/wiki/Unit-testing-with-model-objects

2
Wayne

Je remplace partout dans mon projet TextUtils.isEmpty(...) par ceci:

/**
 * Util class to be used instead of Android classes for Junit tests.
 */
public class Utils {

    /**
     * Returns true if the string is null or 0-length.
     * @param str the string to be examined
     * @return true if str is null or zero length
     */
    public static boolean isEmpty(@Nullable CharSequence str) {
        return str == null || str.length() == 0;
    }
}
2
Roger Alien

Vous devriez utiliser Robolectric:

testImplementation "org.robolectric:robolectric:3.4.2"

Et alors

@RunWith(RobolectricTestRunner::class)
class TestClass {
    ...
}
2
mac229

Suite à la réponse de Johnny, pour intercepter également les appels TextUtils.isEmpty (null), vous pouvez utiliser ce morceau de code.

PowerMockito.mockStatic(TextUtils.class);
PowerMockito.when(TextUtils.isEmpty(any()))
    .thenAnswer((Answer<Boolean>) invocation -> {
        Object s = invocation.getArguments()[0];
        return s == null || s.length() == 0;
    });
0
Hylke Bron