86 votes

Comment simuler la méthode e dans Log

Ici, Utils.java est ma classe à tester et la méthode suivante est appelée dans la classe UtilsTest. Même si je me moque de la méthode Log.e comme indiqué ci-dessous

 @Before
  public void setUp() {
  when(Log.e(any(String.class),any(String.class))).thenReturn(any(Integer.class));
            utils = spy(new Utils());
  }

J'obtiens l'exception suivante

java.lang.RuntimeException: Method e in android.util.Log not mocked. See http://g.co/androidstudio/not-mocked for details.
    at android.util.Log.e(Log.java)
    at com.xxx.demo.utils.UtilsTest.setUp(UtilsTest.java:41)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:78)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:212)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:68)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)

0 votes

Vous pouvez utiliser print ou println (Kotlin)

172voto

Paglian Points 416

Cela a fonctionné pour moi. J'utilise uniquement JUnit et j'ai pu créer une maquette de l'application Log classe sans aucune lib tierce partie très facile. Il suffit de créer un fichier Log.java à l'intérieur de app/src/test/java/android/util avec le contenu :

package android.util; 

public class Log {
    public static int d(String tag, String msg) {
        System.out.println("DEBUG: " + tag + ": " + msg);
        return 0;
    }

    public static int i(String tag, String msg) {
        System.out.println("INFO: " + tag + ": " + msg);
        return 0;
    }

    public static int w(String tag, String msg) {
        System.out.println("WARN: " + tag + ": " + msg);
        return 0;
    }

    public static int e(String tag, String msg) {
        System.out.println("ERROR: " + tag + ": " + msg);
        return 0;
    }

    // add other methods if required...
}

21 votes

C'est vraiment génial. Et cela évite d'avoir à utiliser PowerMockito. 10/10

1 votes

Bonne réponse. Ma théorie est la suivante : si vous devez utiliser des API fantaisie dans les tests unitaires, c'est que votre code n'est pas suffisamment organisé pour être testable à l'unité. Si vous utilisez des bibliothèques externes, utilisez des tests d'intégration avec un runtime et des objets réels. Dans toutes mes applications Android, j'ai créé une classe wrapper LogUtil qui active les logs en fonction d'un drapeau, ce qui me permet d'éviter de mocker la classe Log et d'activer/désactiver les logs avec un drapeau. En production, je supprime de toute façon toutes les déclarations de logs avec progaurd.

4 votes

@MGDevelopert vous avez raison. IMO cette technique/trick devrait être utilisée rarement. Par exemple, je ne le fais que pour le Log car elle est trop omniprésente et passer un wrapper Log partout rend le code moins lisible. Dans la plupart des cas, l'injection de dépendances devrait être utilisée à la place.

43voto

Igor Ganapolsky Points 2851

Vous pouvez mettre ceci dans votre gradle script :

android {
   ...
   testOptions { 
       unitTests.returnDefaultValues = true
   }
}

Cela permettra de décider si les méthodes non simulées d'Android.jar doivent lever des exceptions ou renvoyer des valeurs par défaut.

30 votes

De Docs : Attention : La définition de la propriété returnDefaultValues à true doit être effectuée avec précaution. Les valeurs de retour nulles/zéro peuvent introduire des régressions dans vos tests, ce qui est difficile à déboguer et peut permettre à des tests défaillants de passer. Ne l'utilisez qu'en dernier recours.

26voto

plátano plomo Points 1096

Utilisation de PowerMockito :

@RunWith(PowerMockRunner.class)
@PrepareForTest({Log.class})
public class TestsToRun() {
    @Test
    public void test() {
        PowerMockito.mockStatic(Log.class);
    }
}

Et vous êtes prêt à partir. Soyez conscient que PowerMockito ne simule pas automatiquement les méthodes statiques héritées, donc si vous voulez simuler une classe de journalisation personnalisée qui étend Log, vous devez toujours simuler Log pour des appels tels que MyCustomLog.e().

1 votes

Comment avez-vous obtenu PowerMockRunner dans Gradle ?

4 votes

@IgorGanapolsky Voir ma réponse aquí .

0 votes

Consultez ma réponse dans Kotlin aquí pour la simulation de Log.e et Log.println

8voto

Payal Kothari Points 79

Utilisez PowerMockito.

@RunWith(PowerMockRunner.class)
@PrepareForTest({ClassNameOnWhichTestsAreWritten.class , Log.class})
public class TestsOnClass() {
    @Before
    public void setup() {
        PowerMockito.mockStatic(Log.class);
    }
    @Test
    public void Test_1(){

    }
    @Test
    public void Test_2(){

    }
 }

1 votes

Il convient de mentionner qu'en raison d'un bug, pour JUnit 4.12, utilisez PowerMock >= 1.6.1. Sinon, essayez de fonctionner avec JUnit 4.11.

2voto

Antiohia Points 197

Mockito ne simule pas les méthodes statiques. Utilisez PowerMockito par-dessus. Aquí est un exemple.

1 votes

@user3762991 Vous devez également modifier vos matrices. Vous ne pouvez pas utiliser un matcheur dans le thenReturn(...) déclaration. Vous devez préciser une valeur tangible. Voir plus d'informations aquí

0 votes

Si la méthode e,d,v ne peut pas être mockée, est-ce que mockito devient inutilisable juste à cause de cette limitation ?

2 votes

Si vous ne pouvez pas manger une fourchette, devient-elle inutilisable ? Elle a simplement un autre usage.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X