Log.w()抛出`java.lang.RuntimeException: Stub!`,尽管有`@PrepareForTest(Log.class)`。

huangapple go评论70阅读模式
英文:

Log.w() throws `java.lang.RuntimeException: Stub!` despite `@PrepareForTest(Log.class)`

问题

我正在尝试为间接使用Log.w()的类编写JUnit(5)测试。

当我首次遇到java.lang.RuntimeException: Stub!作为结果时,我迅速发现这是Android开发中众所周知的问题,我可以使用模拟:

@RunWith(PowerMockRunner.class)
@PrepareForTest(Log.class)
class mySusuManager {
...
}

在我的应用的build.gradle中使用以下dependencies {}

testImplementation "org.junit.jupiter:junit-jupiter-api:5.9.1"
testImplementation "org.junit.jupiter:junit-jupiter-params:5.9.1"
testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:5.9.1"
testRuntimeOnly "org.junit.vintage:junit-vintage-engine:5.9.1"

testImplementation 'junit:junit:4.13.2'
testImplementation "org.mockito:mockito-core:4.5.1"
testImplementation "org.powermock:powermock-core:2.0.9"
testImplementation "org.powermock:powermock-module-junit4:2.0.9"
testImplementation "org.powermock:powermock-api-mockito2:2.0.9"

或者使用gradle标志:

android {
    testOptions {
        unitTests.returnDefaultValues = true
    }
}

我尝试了两者(不同时),但仍然遇到了可怕的:

"C:\Program Files\Android\Android Studio\jre\bin\java.exe" ...

java.lang.RuntimeException: Stub!

at android.util.Log.w(Log.java:37)
...

我可能漏掉了什么?

英文:

I am trying to write a JUnit (5) for a class that indirectly uses Log.w().

When I first encountered java.lang.RuntimeException: Stub! as a result, I quickly found out that this is a well known issue in Android development and that I can either use mocking:

@RunWith(PowerMockRunner.class)
@PrepareForTest(Log.class)
class mySusuManager {
...
}

with the following dependencies {} in my app's build.gradle:

testImplementation "org.junit.jupiter:junit-jupiter-api:5.9.1"
testImplementation "org.junit.jupiter:junit-jupiter-params:5.9.1"
testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:5.9.1"
testRuntimeOnly "org.junit.vintage:junit-vintage-engine:5.9.1"

testImplementation 'junit:junit:4.13.2'                         
testImplementation "org.mockito:mockito-core:4.5.1"             
testImplementation "org.powermock:powermock-core:2.0.9"
testImplementation "org.powermock:powermock-module-junit4:2.0.9"
testImplementation "org.powermock:powermock-api-mockito2:2.0.9"

or use a gradle flag:

android {
    testOptions {
        unitTests.returnDefaultValues = true
    }
}

I tried both (not simultaneously), but I am still getting the dreaded:

"C:\Program Files\Android\Android Studio\jre\bin\java.exe" ...

java.lang.RuntimeException: Stub!

	at android.util.Log.w(Log.java:37)
	...

What could I be missing?

答案1

得分: 1

为了所有人的利益,我在这里发布了我如何间接解决我的问题。

大多数现有的SO参考资料都涉及到比今天可用的工具和库版本旧的java.lang.RuntimeException: Stub!问题。

因此,感谢文章如何使用Mockito模拟静态方法,我发现在引入Mockito 3.x后,我不需要使用PowerMock来模拟android.util.Log类。

这是我完成这个任务的步骤:

步骤1:我删除了我的mySusuManagerTest类定义之前的以下内容:

@RunWith(PowerMockRunner.class)
@PrepareForTest(Log.class)

步骤2:我将所有的PowerMock导入替换为一个单一的导入:

import org.mockito.Mockito;

步骤3:在build.gradle中,我用一个单一的mockito-inline类引用替换了所有testImplementation "org.powermock出现的地方以及testImplementation "org.powermock:powermock-core

implementation "org.mockito:mockito-inline:4.11.0"

步骤4:在测试方法中,我只放了一行mockStatic代码:

@Test
void thisIsTheMethodImTesting() {
    Mockito.mockStatic(Log.class);
    // 在此处放置测试 + 断言代码
}
英文:

For the benefit of all, I am posting here how I solved my issue, indirectly.

Most existing SO references to this java.lang.RuntimeException: Stub! issue seem to referring to versions of the tools and libraries that are older than what is available today.

So, thanks to the article How to mock static methods with Mockito, I discovered that with the introduction of Mockito 3.x, I do not need PowerMock to mock the android.util.Log class.

Here is how I accomplished this:

Step 1: I removed the

@RunWith(PowerMockRunner.class)
@PrepareForTest(Log.class)

above my mySusuManagerTest class definition.

Step 2: I replaced all powermock imports with a single:

import org.mockito.Mockito;

Step 3: In build.gradle I replaced all testImplementation "org.powermock occurrences and the testImplementation "org.powermock:powermock-core one, with a single mockito-inline class reference.

implementation "org.mockito:mockito-inline:4.11.0"

Step 4: Inside the test method, I only placed a single mockStatic line:

@Test
void thisIsTheMethodImTesting() {
    Mockito.mockStatic(Log.class);
    // test + assert code here    
}

huangapple
  • 本文由 发表于 2023年1月9日 14:25:42
  • 转载请务必保留本文链接:https://go.coder-hub.com/75053799.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定