Здесь Utils.java - это мой класс для тестирования, а затем - метод, который вызывается в классе UtilsTest. Даже если я издеваюсь над методом Log.e, как показано ниже
@Before
public void setUp() {
when(Log.e(any(String.class),any(String.class))).thenReturn(any(Integer.class));
utils = spy(new Utils());
}
Я получаю следующее исключение
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)
Log
класса, потому что он слишком распространен, и передача оболочки журнала повсюду делает код менее читаемым. В большинстве случаев вместо этого следует использовать внедрение зависимостей.@file:JvmName("Log")
и функции верхнего уровня.Вы можете поместить это в свой скрипт Gradle:
android { ... testOptions { unitTests.returnDefaultValues = true } }
Это решит, должны ли разблокированные методы из android.jar вызывать исключения или возвращать значения по умолчанию.
источник
Если вы используете Kotlin, я бы рекомендовал использовать современную библиотеку, такую как mockk, которая имеет встроенную обработку статики и многих других вещей. Тогда это можно сделать так:
mockkStatic(Log::class) every { Log.v(any(), any()) } returns 0 every { Log.d(any(), any()) } returns 0 every { Log.i(any(), any()) } returns 0 every { Log.e(any(), any()) } returns 0
источник
every { Log.w(any(), any<String>()) } returns 0
Log.wtf
(every { Log.wtf(any(), any<String>()) } returns 0
): компиляции faills с ошибкой:Unresolved reference: wtf
. IDE lint ничего не говорит в коде. Есть идеи ?Log.*
использоватьprintln()
для вывода предназначен Войти?Используя PowerMockito :
@RunWith(PowerMockRunner.class) @PrepareForTest({Log.class}) public class TestsToRun() { @Test public void test() { PowerMockito.mockStatic(Log.class); } }
И тебе хорошо идти. Имейте в виду, что PowerMockito не будет автоматически имитировать унаследованные статические методы, поэтому, если вы хотите имитировать настраиваемый класс ведения журнала, расширяющий журнал, вы все равно должны имитировать журнал для таких вызовов, как MyCustomLog.e ().
источник
Используйте 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(){ } }
источник
С помощью логгера Android
PowerMock
можно имитировать статические методы Log.i / e / w . Конечно, в идеале вы должны создать интерфейс регистрации или фасад и предоставить способ регистрации к различным источникам.Это полное решение на Котлине:
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") } }
не забудьте добавить зависимости в 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' }
Чтобы издеваться над
Log.println
методом, используйте:Mockito.`when`(Log.println(anyInt(), any(), any())).then { println(it.arguments[2] as String) 1 }
источник
Я бы рекомендовал использовать древесину для лесозаготовок.
Хотя он не будет ничего регистрировать при запуске тестов, но он не приведет к излишнему провалу ваших тестов, как это делает класс журнала Android. Timber дает вам много удобных средств управления как отладкой, так и производственной сборкой вашего приложения.
источник
Благодаря ответу @Paglian и комментарию @ Miha_x64 я смог заставить то же самое работать для kotlin.
Добавьте следующий файл Log.kt в
app/src/test/java/android/util
@file:JvmName("Log") package android.util fun e(tag: String, msg: String, t: Throwable): Int { println("ERROR: $tag: $msg") return 0 } fun e(tag: String, msg: String): Int { println("ERROR: $tag: $msg") return 0 } fun w(tag: String, msg: String): Int { println("WARN: $tag: $msg") return 0 } // add other functions if required...
И вуаля, ваши вызовы Log.xxx должны вместо этого вызывать эти функции.
источник
Mockito не издевается над статическими методами. Используйте PowerMockito поверх. Вот пример.
источник
thenReturn(...)
заявлении. Вам нужно указать материальную ценность. Больше информации здесьДругое решение - использовать Robolectric. Если хотите попробовать, проверьте его настройку .
В вашем модуле build.gradle добавьте следующее
testImplementation "org.robolectric:robolectric:3.8" android { testOptions { unitTests { includeAndroidResources = true } } }
И в вашем тестовом классе
@RunWith(RobolectricTestRunner.class) public class SandwichTest { @Before public void setUp() { } }
В более новых версиях Robolectric (протестированных с 4.3) ваш тестовый класс должен выглядеть следующим образом:
@RunWith(RobolectricTestRunner.class) @Config(shadows = ShadowLog.class) public class SandwichTest { @Before public void setUp() { ShadowLog.setupLogging(); } // tests ... }
источник
Если вы используете org.slf4j.Logger, то просто издевательство над Logger в тестовом классе с помощью PowerMockito сработало для меня.
@RunWith(PowerMockRunner.class) public class MyClassTest { @Mock Logger mockedLOG; ... }
источник
Расширение ответа от kosiara для использования PowerMock и Mockito в Java с JDK11 для имитации
android.Log.v
метода с помощьюSystem.out.println
модульного тестирования в Android Studio 4.0.1.Это полное решение на Java:
import android.util.Log; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mockito; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; import org.powermock.api.mockito.PowerMockito; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; import static org.mockito.ArgumentMatchers.any; @RunWith(PowerMockRunner.class) @PrepareForTest(Log.class) public class MyLogUnitTest { @Before public void setup() { // mock static Log.v call with System.out.println PowerMockito.mockStatic(Log.class); Mockito.when(Log.v(any(), any())).then(new Answer<Void>() { @Override public Void answer(InvocationOnMock invocation) throws Throwable { String TAG = (String) invocation.getArguments()[0]; String msg = (String) invocation.getArguments()[1]; System.out.println(String.format("V/%s: %s", TAG, msg)); return null; } }); } @Test public void logV() { Log.v("MainActivity", "onCreate() called!"); } }
Не забудьте добавить зависимости в файл build.gradle вашего модуля, в котором существует ваш модульный тест:
dependencies { ... /* PowerMock android.Log for OpenJDK11 */ def mockitoVersion = "3.5.7" def powerMockVersion = "2.0.7" // optional libs -- Mockito framework testImplementation "org.mockito:mockito-core:${mockitoVersion}" // optional libs -- power mock testImplementation "org.powermock:powermock-module-junit4:${powerMockVersion}" testImplementation "org.powermock:powermock-api-mockito2:${powerMockVersion}" testImplementation "org.powermock:powermock-module-junit4-rule:${powerMockVersion}" testImplementation "org.powermock:powermock-module-junit4-ruleagent:${powerMockVersion}" }
источник