簡體   English   中英

不能在 Java 中模擬最終的 class

[英]Can not Mock a final class in Java

我有一個單元測試,看起來像這樣:

DefaultCloudFoundryOperations cfOperationsMock = mock(DefaultCloudFoundryOperations.class);
        when(cfOperationsMock.getSpace()).thenReturn("development");
        when(cfOperationsMock.getOrganization()).thenReturn("cloud.foundry.cli");

        UserAdmin userAdminMock = mock(UserAdmin.class);
        when(cfOperationsMock.userAdmin()).thenReturn(userAdminMock);

        Mono<SpaceUsers> monoMock = (Mono<SpaceUsers>) mock(Mono.class);
        when(userAdminMock.listSpaceUsers(any())).thenReturn(monoMock);

        SpaceUsers spaceUsersMock = mock(SpaceUsers.class);
        when(monoMock.block()).thenReturn(spaceUsersMock);
        when(spaceUsersMock.getDevelopers())
            .thenReturn(Arrays.asList("one", "two", "three", "four"));

        SpaceDevelopersProvider spaceDeveloperProvider = new SpaceDevelopersProvider(
            cfOperationsMock);

        String spaceDevelopers = spaceDeveloperProvider.getSpaceDevelopers();

        assertThat(spaceDevelopers, is(Arrays.asList("one", "two", "three", "four")));

和一個 gradle 依賴項,如下所示:

dependencies {
    // This dependency is exported to consumers, that is to say found on their compile classpath.
    api 'org.apache.commons:commons-math3:3.6.1'

    // This dependency is used internally, and not exposed to consumers on their own compile classpath.
    implementation 'com.google.guava:guava:28.0-jre'

    compile 'info.picocli:picocli:4.2.0'
    compile 'org.yaml:snakeyaml:1.26'

    // Use JUnit test framework
    testRuntime("org.junit.jupiter:junit-jupiter-engine:5.5.2")
    testRuntime("org.junit.platform:junit-platform-runner:1.5.2")
    testImplementation('org.junit.jupiter:junit-jupiter:5.5.2')

    testImplementation 'org.hamcrest:hamcrest:2.2'
    testImplementation "org.mockito:mockito-core:2.+"


    compile 'io.swagger.parser.v3:swagger-parser:2.0.19'

    compile 'org.cloudfoundry:cloudfoundry-client-reactor:4.6.0.RELEASE'
    compile 'org.cloudfoundry:cloudfoundry-operations:4.6.0.RELEASE'}

當我嘗試執行此測試時,我收到:

org.mockito.exceptions.base.MockitoException: 
Mockito cannot mock this class: class org.cloudfoundry.operations.DefaultCloudFoundryOperations.
Can not mock final classes with the following settings :
 - explicit serialization (e.g. withSettings().serializable())
 - extra interfaces (e.g. withSettings().extraInterfaces(...))

有沒有人有想法,我如何測試它,或者我應該如何調整代碼? 我花了很多時間,但找不到真正適合我的解決方案。

謝謝

在您的生產代碼中(與您的測試代碼相反),不要使用DefaultCloudFoundryOperations ,而是使用它實現的接口: CloudFoundryOperations

例如,像這樣聲明:

public class SpaceDevelopersProvider {
  private final CloudFoundryOperations cfOps;
  public SpaceDevelopersProvider(CloudFoundryOperations cfOps) {
    this.cfOps = cfOps;
  }
  ...
}

然后,您可以模擬該界面。

CloudFoundryOperations cfOperationsMock = mock(CloudFoundryOperations.class);
...
SpaceDevelopersProvider spaceDeveloperProvider = new SpaceDevelopersProvider(cfOperationsMock);

在運行時,當您使用 Mockito 模擬 object 時,它將創建一個代理 class 並擴展您想要模擬的 ZA2F2ED4F8EBC2CBBD4ZC21A 與 java 一樣,最終的 class 無法擴展,因此 mockito 無法模擬最終的 ZA2F2ED4F8EBC2CBB14C21A29DZ4。

從 class ( DefaultCloudFoundryOperations ) 的名稱來看,我首先 class 實現了一個接口,其次,所有消費者都將采用該接口,而不是具體的 ZA2F2ED4F8EBC2CBB4C21A29DC40AB61D。

如果我對的,您可以模擬接口而不是具體的 class。

如前所述,這是一個猜測!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM