Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mocking final classes #285

Closed
ghost opened this issue Sep 6, 2018 · 14 comments
Closed

Mocking final classes #285

ghost opened this issue Sep 6, 2018 · 14 comments

Comments

@ghost
Copy link

ghost commented Sep 6, 2018

Hi,
Kotlin classes are final by default, when i use this library to test kotlin classes, it gives me the following error:

org.mockito.exceptions.base.MockitoException: 
Cannot mock/spy class com.app.network.entity.Movies
Mockito cannot mock/spy because :
 - final class

How do i test this? Please assist

@ZakTaccardi
Copy link

Use mock-maker-inline to mock final classes

@ghost
Copy link
Author

ghost commented Sep 7, 2018 via email

@bohsen
Copy link

bohsen commented Sep 7, 2018

Could you create a MWE for your issue? It's always easier to help if you have a bit more details.

@nhaarman
Copy link
Collaborator

Using mock-maker-inline should fix the issue, perhaps you've misconfigured it? See the original repo for details.

@bbaldino
Copy link

I started seeing this when upgrading to mockito-kotlin2. I've got mock-maker-inline set up (and was working fine with mockito-kotlin 1.5.0), but after upgrading to v2 I'm seeing:

Caused by: org.mockito.exceptions.base.MockitoException:
Mockito cannot mock this class: class org.jitsi.jibri.util.OsDetector.
Can not mock final classes with the following settings :
 - explicit serialization (e.g. withSettings().serializable())
 - extra interfaces (e.g. withSettings().extraInterfaces(...))

The class that causes it is final, but has no special settings that I know of:

enum class OsType {
    MAC,
    LINUX,
    UNSUPPORTED
}

class OsDetector {
    fun getOsType(): OsType {
        return when (System.getProperty("os.name")) {
            "Mac OS X" -> OsType.MAC
            "Linux" -> OsType.LINUX
            else -> OsType.UNSUPPORTED
        }
    }
}

@manerfan
Copy link

manerfan commented Jan 3, 2019

I started seeing this when upgrading to mockito-kotlin2. I've got mock-maker-inline set up (and was working fine with mockito-kotlin 1.5.0), but after upgrading to v2 I'm seeing:

Caused by: org.mockito.exceptions.base.MockitoException:
Mockito cannot mock this class: class org.jitsi.jibri.util.OsDetector.
Can not mock final classes with the following settings :
 - explicit serialization (e.g. withSettings().serializable())
 - extra interfaces (e.g. withSettings().extraInterfaces(...))

The class that causes it is final, but has no special settings that I know of:

enum class OsType {
    MAC,
    LINUX,
    UNSUPPORTED
}

class OsDetector {
    fun getOsType(): OsType {
        return when (System.getProperty("os.name")) {
            "Mac OS X" -> OsType.MAC
            "Linux" -> OsType.LINUX
            else -> OsType.UNSUPPORTED
        }
    }
}

try to add

<dependency>
    <groupId>net.bytebuddy</groupId>
    <artifactId>byte-buddy</artifactId>
    <scope>test</scope>
</dependency>

to the dependencies

@meganzhao10
Copy link

I started seeing this when upgrading to mockito-kotlin2. I've got mock-maker-inline set up (and was working fine with mockito-kotlin 1.5.0), but after upgrading to v2 I'm seeing:

Caused by: org.mockito.exceptions.base.MockitoException:
Mockito cannot mock this class: class org.jitsi.jibri.util.OsDetector.
Can not mock final classes with the following settings :
 - explicit serialization (e.g. withSettings().serializable())
 - extra interfaces (e.g. withSettings().extraInterfaces(...))

The class that causes it is final, but has no special settings that I know of:

enum class OsType {
    MAC,
    LINUX,
    UNSUPPORTED
}

class OsDetector {
    fun getOsType(): OsType {
        return when (System.getProperty("os.name")) {
            "Mac OS X" -> OsType.MAC
            "Linux" -> OsType.LINUX
            else -> OsType.UNSUPPORTED
        }
    }
}

try to add

<dependency>
    <groupId>net.bytebuddy</groupId>
    <artifactId>byte-buddy</artifactId>
    <scope>test</scope>
</dependency>

to the dependencies

I have the same error message when mocking JWTVerifier class (Java, not Kotlin), but adding the bytebuddy dependency doesn't solve the issue for me. This seems like a limitation of Mockito (Section 39: https://www.javadoc.io/doc/org.mockito/mockito-core/2.2.7/org/mockito/Mockito.html#Mocking_Final). Is there any way to bypass it?

Mockito cannot mock this class: class com.auth0.jwt.JWTVerifier.
Can not mock final classes with the following settings :
 - explicit serialization (e.g. withSettings().serializable())
 - extra interfaces (e.g. withSettings().extraInterfaces(...))
public final class JWTVerifier implements com.auth0.jwt.interfaces.JWTVerifier {
    private final Algorithm algorithm;
    final Map<String, Object> claims;
    private final Clock clock;
    private final JWTParser parser;

    JWTVerifier(Algorithm algorithm, Map<String, Object> claims, Clock clock) {
        this.algorithm = algorithm;
        this.claims = Collections.unmodifiableMap(claims);
        this.clock = clock;
        this.parser = new JWTParser();
    }

    static Verification init(Algorithm algorithm) throws IllegalArgumentException {
        return new JWTVerifier.BaseVerification(algorithm);
    }

    public DecodedJWT verify(String token) throws JWTVerificationException {
        DecodedJWT jwt = new JWTDecoder(this.parser, token);
        return this.verify((DecodedJWT)jwt);
    }

    public DecodedJWT verify(DecodedJWT jwt) throws JWTVerificationException {
        this.verifyAlgorithm(jwt, this.algorithm);
        this.algorithm.verify(jwt);
        this.verifyClaims(jwt, this.claims);
        return jwt;
    }
    ...
}

@bohsen
Copy link

bohsen commented Apr 27, 2020

@meganzhao10 A lot has changed since mockito-kotlin 1.5.0. This looks like a problem related to the creation of your mock.

Could you please share the test.

@meganzhao10
Copy link

@bohsen This is the test file. I'm able to run the tests successfully in IntelliJ. But mvn test failed with the message that I think it's part of Mockito limitations:

class ControllerTest {

    private Controller controller;

    @Mock
    private JWTVerifier verifier;

    @BeforeEach
    void setUp() {
        initMocks(this);
        controller = new Controller(verifier);
    }

    @Test
    void testFunc1() {
        ...
    }
    ...
}

I also included the pom.xml dependencies if that's helpful

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.9.10.3</version>
        </dependency>
        <dependency>
            <groupId>io.lettuce</groupId>
            <artifactId>lettuce-core</artifactId>
            <version>5.2.1.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
            <version>3.9.0</version>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-engine</artifactId>
            <version>${junit-jupiter.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.github.stefanbirkner</groupId>
            <artifactId>system-rules</artifactId>
            <version>1.17.2</version>
        </dependency>
        <dependency>
            <groupId>org.mockito</groupId>
            <artifactId>mockito-core</artifactId>
            <version>2.24.0</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.mockito</groupId>
            <artifactId>mockito-junit-jupiter</artifactId>
            <version>${mockito.version}</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

@bohsen
Copy link

bohsen commented Apr 27, 2020

@meganzhao10 Have you tried including mockito-inline artifact in your dependencies?

@bohsen
Copy link

bohsen commented Apr 27, 2020

@meganzhao10 If the Controller only has a dependency on the abstraction com.auth0.jwt.interfaces.JWTVerifier then I don't see any reason why this shouldn't work.

@meganzhao10
Copy link

@bohsen You're right that it should have worked. I built a Java container - the test passes with the base image 3.6.3-jdk-11-slim but failed with 3.6.3-jdk-14-slim. Then I switched my Java version from 14 to 11 and mvn test works, though I'm not sure it why the mock doesn't work with Java 14

@bohsen
Copy link

bohsen commented Apr 28, 2020

@meganzhao10 Maybe share this with the original Mockito project? I'm not sure if their CI test suite tests against java 14, but IMO it would make sense to create an issue on this.

@nmattocks-pfizer
Copy link

This looks like it's tracked mockito/mockito#2436
Commenting because this ranks higher on Google search.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants