如何在Log中模拟方法e

时间:2016-04-22 07:20:24

标签: android junit mockito

这里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)

12 个答案:

答案 0 :(得分:85)

这对我有用。我只使用JUnit而且我能够非常轻松地模拟Log.java而没有任何第三方库。只需在app/src/test/java/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... } ,其内容为:

replacement

答案 1 :(得分:26)

您可以将其放入您的gradle脚本中:

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

这将决定android.jar中的unmocked方法是否应该抛出异常或返回默认值。

答案 2 :(得分:23)

使用PowerMockito

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

你很高兴去。请注意,PowerMockito不会自动模拟继承的静态方法,因此如果要模拟扩展Log的自定义日志记录类,则仍必须模拟Log以获取MyCustomLog.e()之类的调用。

答案 3 :(得分:7)

使用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(){

    }
 }

答案 4 :(得分:4)

如果使用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

答案 5 :(得分:3)

多亏了@Paglian的回答和@ Miha_x64的评论,我才能够使Kotlin发挥同样的作用。

app/src/test/java/android/util中添加以下Log.kt文件

@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的调用应改为调用这些函数。

答案 6 :(得分:2)

Mockito不会模拟静态方法。在顶部使用PowerMockito。 Here就是一个例子。

答案 7 :(得分:2)

使用PowerMock可以从Android记录器中模拟 Log.i / e / w静态方法。当然,理想情况下,您应该创建一个日志记录界面或外观,并提供一种记录到不同来源的方法。

这是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")
    }
}

记住要在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
}

答案 8 :(得分:2)

我建议您使用timber进行日志记录。

尽管在运行测试时它不会记录任何内容,但不会像android Log类那样不必要地使测试失败。 Timber使您可以方便地控制应用程序的调试和生产版本。

答案 9 :(得分:0)

另一种解决方案是使用Robolectric。如果您想尝试一下,请检查its setup

在模块的build.gradle中,添加以下内容

testImplementation "org.robolectric:robolectric:3.8"

android {
  testOptions {
    unitTests {
      includeAndroidResources = true
    }
  }
}

在你的考试班上,

@RunWith(RobolectricTestRunner.class)
public class SandwichTest {
  @Before
  public void setUp() {
  }
}

答案 10 :(得分:0)

如果您使用的是org.slf4j.Logger,那么只需使用PowerMockito在测试类中模拟Logger即可。

@RunWith(PowerMockRunner.class)
public class MyClassTest {

@Mock
Logger mockedLOG;

...
}

答案 11 :(得分:0)

扩展了kosiara中在 Java 中将 PowerMock Mockito 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}"
}