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());
}
Je reçois 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)
Cela a fonctionné pour moi. J'utilise uniquement JUnit et j'ai pu simuler la Log
classe sans bibliothèque tierce très facile. Il suffit de créer un fichier Log.Java
dans app/src/test/Java/Android/util
avec le contenu:
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...
}
Vous pouvez mettre ceci dans votre script gradle:
Android {
...
testOptions {
unitTests.returnDefaultValues = true
}
}
Cela déterminera si les méthodes non gênées depuis Android.jar doivent générer des exceptions ou renvoyer des valeurs par défaut.
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. Sachez que PowerMockito ne simulera pas automatiquement les méthodes statiques héritées. Ainsi, si vous souhaitez simuler une classe de journalisation personnalisée qui étend le journal, vous devez toujours simuler le journal d'appels tels que MyCustomLog.e ().
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(){
}
}
En utilisant PowerMock
, vous pouvez vous moquer de Log.i/e/w méthodes statiques à partir de l'enregistreur Android. Bien sûr, idéalement, vous {créez une interface de journalisation ou une façade} et fournissez un moyen de consigner vos données dans différentes sources.
C’est une solution complète chez Kotlin:
import org.powermock.modules.junit4.PowerMockRunner
import org.powermock.api.mockito.PowerMockito
import org.powermock.core.classloader.annotations.PrepareForTest
/**
* Logger Unit tests
*/
@RunWith(PowerMockRunner::class)
@PrepareForTest(Log::class)
class McLogTest {
@Before
fun beforeTest() {
PowerMockito.mockStatic(Log::class.Java)
Mockito.`when`(Log.i(any(), any())).then {
println(it.arguments[1] as String)
1
}
}
@Test
fun logInfo() {
Log.i("TAG1,", "This is a samle info log content -> 123")
}
}
n'oubliez pas d'ajouter des dépendances dans gradle:
dependencies {
testImplementation "junit:junit:4.12"
testImplementation "org.mockito:mockito-core:2.15.0"
testImplementation "io.kotlintest:kotlintest:2.0.7"
testImplementation 'org.powermock:powermock-module-junit4-rule:2.0.0-beta.5'
testImplementation 'org.powermock:powermock-core:2.0.0-beta.5'
testImplementation 'org.powermock:powermock-module-junit4:2.0.0-beta.5'
testImplementation 'org.powermock:powermock-api-mockito2:2.0.0-beta.5'
}
Pour simuler la méthode Log.println
, utilisez:
Mockito.`when`(Log.println(anyInt(), any(), any())).then {
println(it.arguments[2] as String)
1
}
Mockito ne se moque pas des méthodes statiques. Utilisez PowerMockito sur le dessus. Here est un exemple.
Je recommanderais d'utiliser bois pour votre exploitation forestière.
Bien qu'il n'enregistre rien lors de l'exécution des tests, il n'échoue pas inutilement vos tests comme le fait la classe Android Log. Timber vous donne beaucoup de contrôle sur les versions de débogage et de production de votre application.