如何在Log中模拟方法e

use*_*991 57 junit android 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());
  }
Run Code Online (Sandbox Code Playgroud)

我收到以下异常

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)
Run Code Online (Sandbox Code Playgroud)

Pag*_*ian 110

这对我有用.我只使用JUnit而且我能够在没有任何第三方库的情况下模拟Log该类非常容易.只要创建一个文件里面有内容:Log.javaapp/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...
}
Run Code Online (Sandbox Code Playgroud)

  • 这是血腥的辉煌.它躲过了对PowerMockito的需求.10/10 (12认同)
  • 效果很好.在复制粘贴之前,添加包名:**package android.util;** (4认同)
  • @MGDevelopert你是对的。IMO几乎不应使用此技术/技巧。例如,我只对Log类进行此操作,因为它太普遍了,并且在各处传递Log包装器会使代码的可读性降低。在大多数情况下,应该使用依赖注入。 (2认同)
  • 为我工作,但仅作为 Java 文件。转换为 Kotlin 类会导致 calssdef 异常 (2认同)

Igo*_*sky 31

你可以把它放到你的gradle脚本中:

android {
   ...
   testOptions { 
       unitTests.returnDefaultValues = true
   }
}
Run Code Online (Sandbox Code Playgroud)

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

  • *来自Docs:***注意:**将returnDefaultValues属性设置为true应该小心.null/zero返回值可能会在测试中引入回归,这些回归难以调试并且可能允许失败的测试通过.**只能将它作为最后的手段使用.** (22认同)

plá*_*omo 26

使用PowerMockito:

@RunWith(PowerMockRunner.class)
@PrepareForTest({Log.class})
public class TestsToRun() {
    @Test
    public void test() {
        PowerMockito.mockStatic(Log.class);
    }
}
Run Code Online (Sandbox Code Playgroud)

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

  • @IgorGanapolsky看到我的回答[这里](http://stackoverflow.com/a/39172168/5495432). (3认同)
  • PowerMockito 在 2019 年仍然是 Kotiln 的流行解决方案吗?或者我们应该看看其他模拟库(即 MockK)。 (2认同)

Gre*_*nis 11

如果使用Kotlin,我建议您使用像嘲笑之类的现代库,该库具有对静电和许多其他东西的内置处理。然后就可以做到这一点:

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
Run Code Online (Sandbox Code Playgroud)

  • 如果你想捕获 Log.w 添加:`every { Log.w(any(), any<String>()) } returns 0` (2认同)
  • 太棒了+1!!...这在我使用Mockk时对我有用。 (2认同)
  • 我可以使用mockk调用`Log.*`使用`println()`来输出预期的Log吗? (2认同)

Pay*_*ari 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(){

    }
 }
Run Code Online (Sandbox Code Playgroud)


kos*_*cki 6

使用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")
    }
}
Run Code Online (Sandbox Code Playgroud)

记得在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'
}
Run Code Online (Sandbox Code Playgroud)

模拟Log.println方法使用:

Mockito.`when`(Log.println(anyInt(), any(), any())).then {
    println(it.arguments[2] as String)
    1
}
Run Code Online (Sandbox Code Playgroud)


Abe*_*bel 6

感谢@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...
Run Code Online (Sandbox Code Playgroud)

瞧,您对 Log.xxx 的调用应该调用这些函数。


Tos*_*ohn 5

我建议您使用木材进行伐木。

虽然它在运行测试时不会记录任何内容,但它不会像 android Log 类那样不必要地使您的测试失败。Timber 为您提供了对应用程序的调试和生产构建的很多方便的控制。


Hen*_*eMS 5

@Paglian 答案的 kotlin 版本,无需模拟 android.util.Log 进行 JUnit 测试:)

强调:

1 -> 顶部的包名称

2 -> 函数顶部的注释

package android.util

class Log {
    companion object {
        fun d(tag: String, msg: String): Int {
            println("DEBUG: $tag: $msg")
            return 0
        }

        @JvmStatic
        fun i(tag: String, msg: String): Int {
            println("INFO: $tag: $msg")
            return 0
        }

        @JvmStatic
        fun w(tag: String, msg: String): Int {
            println("WARN: $tag: $msg")
            return 0
        }

        @JvmStatic
        fun w(tag: String, msg: String, exception: Throwable): Int {
            println("WARN: $tag: $msg , $exception")
            return 0
        }

        @JvmStatic
        fun e(tag: String, msg: String): Int {
            println("ERROR: $tag: $msg")
            return 0
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 还可以做得更简单。使用“对象”而不是类,您可以删除“伴随对象” (2认同)

Ant*_*hia 2

Mockito 不模拟静态方法。在上面使用 PowerMockito。是一个例子。

  • 如果你不能吃叉子,它就不能用了吗?它只是有另一个目的。 (2认同)