不能使用Mockito 2模拟最终的Kotlin课程

时间:2017-07-17 11:56:10

标签: java android unit-testing mockito kotlin

我无法使用Mockito 2模拟Kotlin决赛课。我还在使用Robolectric。

这是我的测试代码:

for

当我们尝试在@RunWith(RobolectricTestRunner.class) @Config(constants = BuildConfig.class, sdk = 21) public class Test { // more mocks @Mock MyKotlinLoader kotlinLoader; @Before public void setUp() { MockitoAnnotations.initMocks(this); } } 方法中初始化模拟时,测试失败。

另外,我在代码中使用了以下gradle依赖项:

setUp()

所有其他单元测试都使用此配置,但是一旦我尝试模拟Kotlin类,它就会抛出以下错误:

testCompile 'org.robolectric:robolectric:3.3.2' testCompile 'org.robolectric:shadows-multidex:3.3.2' testCompile 'org.robolectric:shadows-support-v4:3.3.2' testCompile("org.powermock:powermock-api-mockito2:1.7.0") { exclude module: 'hamcrest-core' exclude module: 'objenesis' } testCompile 'junit:junit:4.12' testCompile 'org.mockito:mockito-inline:2.8.9'

请注意我使用的是Mockito版本2,我使用的是Mockito cannot mock/spy because : - final class依赖项,它可以自动启用模拟最终类的功能。

8 个答案:

答案 0 :(得分:13)

PowerMock实现了自己的MockMaker,这导致与Mockito mock-maker-inline不兼容,即使PowerMock刚刚作为依赖项添加而未被使用。如果路径中存在两个org.mockito.plugins.MockMaker,则可以使用任何一个org/powermock/extensions/configuration.properties,其中一个未确定。

然而,PowerMock可以将调用委托给另一个MockMaker,然后在没有PowerMock的情况下运行测试。从PowerMock 1.7.0开始,可以使用PowerMock配置对其进行配置。

可以通过创建文件mockito.mock-maker-class=mock-maker-inline 并设置:

来配置MockMaker
Z

使用Mockito mock-maker-inline和PowerMock的示例:https://github.com/powermock/powermock-examples-maven/tree/master/mockito2

答案 1 :(得分:2)

自Mockito 2.1.0起,就有可能模拟最终类型,枚举和最终方法。在原始问题的注释中已经提到了它。

为此,您需要创建一个文件夹(如果不存在)test/resources/mockito-extensions,然后在其中添加名称为org.mockito.plugins.MockMaker的文件并添加以下行:

mock-maker-inline

enter image description here

链接到documentationtutorial

答案 2 :(得分:1)

您可以使用Powermock,例如:

import static org.powermock.api.mockito.PowerMockito.mock;
import static org.powermock.api.mockito.PowerMockito.spy;
import static org.powermock.api.mockito.PowerMockito.when;

@RunWith(RobolectricTestRunner.class)
@Config(constants = BuildConfig.class, sdk = 21)
@PowerMockIgnore({ "org.mockito.*", "org.robolectric.*", "android.*" })
@PrepareForTest({FinalClass1.class, FinalClass2.class})
public class Test {
    @Rule
    public PowerMockRule rule = new PowerMockRule();

    ... // your code here
}

答案 3 :(得分:0)

让我们编程接口,而不是实现。您可以提取接口,在代码中使用它并模拟它。例如,以下内容不起作用:

import com.nhaarman.mockito_kotlin.mock
class MyFinalClass {...}
(snip)
private val MyFinalClass = mock()

所以让我们提取一个界面:

class MyFinalClass : MyInterface {...}
(snip)
private val MyInterface = mock()

答案 4 :(得分:0)

因为在kotlin中,所有类默认都是final。

您还应该考虑将native query添加到类声明中。

示例:jpql

答案 5 :(得分:0)

Kotlin使装饰器模式完全简单且简洁:

open class OpenClass() : SomeInterface by FinalClass()

实际上,这将对SomeInterface包装类中的FinalClass()实例进行包装调用来覆盖每个open成员。然后,您可以将此包装器注入测试中。

我不得不在目标类位于库中的项目上求助,并且all-open编译器插件似乎无法触及。

答案 6 :(得分:0)

尝试将此以下依赖项添加到您的build.gradle中。

{{1}}

替换为您的模仿版本,而不是2.8.47。这将帮助您避免使用powermock解决问题。

请查看下面的链接,以了解此事情的工作原理。

How to mock a final class with mockito

答案 7 :(得分:0)

mock-maker-inline的工作方式与其他答案中所指出的一样。但这真的很慢。您可以使用all-open插件来避免此问题。

为此,您需要:

  1. 创建注释:
annotation class Mockable
  1. 激活build.gradle文件中的全开:
dependencies {
  classpath "org.jetbrains.kotlin:kotlin-allopen:$kotlin_version"
}

apply plugin: 'kotlin-allopen'

allOpen {
  annotation('com.example.Mockable')
}
  1. 注释您要模拟的类:
@Mockable
class Foo {
  fun calculateTheFoo(): Int {
    sleep(1_000) // Difficult things here
    return 1
  }
}

如果您想了解更多信息,可以阅读我的博客文章,我在其中详细介绍了这些内容:Mocking Kotlin classes with Mockito — the fast way