Junit5 模拟静态方法

问题描述 投票:0回答:6

我想在 JUnit 5 中模拟静态方法。但不幸的是,JUnit 5 不支持 Mockito。除了恢复到 JUnit 4 之外,还有其他方法可以实现相同的目的吗?

unit-testing mockito powermock junit5
6个回答
49
投票

从 Mockito 3.4.0 (2020-07-10) 开始,即使在 JUnit 5 中也可以开箱即用地模拟静态方法,无需任何扩展。

在文档中,您可以找到一个示例:48。模拟静态方法(自 3.4.0 起)

重要提示:您需要使用内联模拟制作器。所以使用的依赖不是核心依赖:

        <dependency>
            <groupId>org.mockito</groupId>
            <artifactId>mockito-inline</artifactId>
            <version>3.4.6</version>
            <scope>test</scope>
        </dependency>

示例: 被测班级:

package teststatics;

public class FooWithStatics {
    public static Long noParameters() {
        return System.currentTimeMillis();
    }
    public static String oneParameter(String param1) {
        return param1.toUpperCase();
    }
}

测试班:

package teststatics;

import org.junit.jupiter.api.Test;
import org.mockito.MockedStatic;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;

public class FooWithStaticsTest {

    @Test
    void testStatic() {
        // Before mock scope, usual behavior.
        assertNotEquals(0L, FooWithStatics.noParameters());
        assertNotEquals("yyy", FooWithStatics.oneParameter("xxx"));

        // Mock scope
        try (MockedStatic mocked = mockStatic(FooWithStatics.class)) {

            // Mocking
            mocked.when(FooWithStatics::noParameters).thenReturn(0L);
            mocked.when(() -> FooWithStatics.oneParameter("xxx")).thenReturn("yyy");

            // Mocked behavior
            assertEquals(0L, FooWithStatics.noParameters());
            assertEquals("yyy", FooWithStatics.oneParameter("xxx"));

            // Verifying mocks.
            mocked.verify(times(1), FooWithStatics::noParameters);
            mocked.verify(times(1), () -> FooWithStatics.oneParameter("xxx"));
        }

        // After mock scope returns to usual behavior.
        assertNotEquals(0L, FooWithStatics.noParameters());
        assertNotEquals("yyy", FooWithStatics.oneParameter("xxx"));
    }
}

15
投票

简短的回答是否定的,因为 Mockito 团队已经完成了他们的工作,正在等待 JUnit 团队扩展,并且在这里进行了很多讨论。

通过一些开销,您可以:由于 JUnit 5 提供了对运行旧版 JUnit 4 的支持,因此您可以使用 Mockito。因此,您可以在 Junit4 中为这些情况创建测试:

使用 gradlemvn 进行迁移设置的示例项目。从那里我将 PowerMock 2.0 beta 与 Mockito 2 一起使用。


9
投票

Mockito 目前不提供静态方法模拟的原因是因为人们普遍认为静态方法不需要被模拟。

但是,Mockito here 有一个开放项目讨论该问题。

虽然这不能回答您的问题,但总的来说,它会告诉您为什么根本不需要该功能,或者允许您加入您的想法的对话。


5
投票
  1. 确保您的 POM 文件中有

    mockito-inline
    依赖项

    <dependency>
        <groupId>org.mockito</groupId>
        <artifactId>mockito-inline</artifactId>
        <version>3.6.28</version>
        <scope>test</scope>
    </dependency>
    
  2. 在我的例子中,我必须测试抛出异常的场景

    encode()
    类的静态方法
    URLEncoder
    ,所以为此

    try (MockedStatic theMock  = mockStatic(URLEncoder.class)) {
        theMock.when(() -> URLEncoder.encode("Test/11", StandardCharsets.UTF_8.toString()))
        .thenThrow(UnsupportedEncodingException.class);
        when(restClient.retrieveByName("Test%2F11")).thenReturn(null);
        Assertions.assertThrows(ResponseStatusException.class, ()->service.retrieveByName("Test/11"));
    }
    

2
投票

您可以使用

mockito-inline
工件来实现静态方法的Mocking。

  1. 添加maven依赖。
<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-inline</artifactId>
    <version>5.2.0</version>
    <scope>test</scope>
</dependency>
  1. 可选:如果遇到问题,请排除mockito-core,因为它已经包含在mockito-inline中
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
    <exclusions>
        <exclusion>
            <groupId>org.mockito</groupId>
            <artifactId>mockito-core</artifactId>
        </exclusion>
        <exclusion>
            <artifactId>mockito-junit-jupiter</artifactId>
            <groupId>org.mockito</groupId>
        </exclusion>
    </exclusions>
</dependency>
  1. 举例说明:
class FilesUtility{
    public static boolean something(String x , String y){
        return true;
    }
}
  1. 测试用例:
@Test
void testStaticMethod() {
    try (MockedStatic<? extends FilesUtility> mocked = 
       mockStatic(FilesUtility.class, CALLS_REAL_METHODS)) {

    mocked
        when(() -> FilesUtility.something(any(), any()))
        .thenReturn(false);
    }
}

重要: 默认行为是不执行任何操作,但也可以在创建模拟时通过显式指定 CALLS_REAL_METHODS 来提供 Answer

mockStatic(FilesUtility.class, CALLS_REAL_METHODS)

因此,如果您的模拟静态方法在内部调用该模拟类中的任何其他方法,您也不必模拟它们的行为 - 您可以通过指定 
CALLS_REAL_METHODS

参数来保持它们的默认行为。它相当于对该类进行

Spying


0
投票

JMockit 用于模拟测试边界之外的外部依赖项,类似于 Mockito 和其他此类模拟库。 JMockit 最重要的功能是它允许我们模拟任何东西,甚至是其他库难以模拟的东西,例如构造函数、静态方法和最终方法。它甚至还允许模拟成员字段和初始化块。

按照以下步骤启用JMockit:

JMockit 工件位于中央 Maven 存储库中,在 pom.xml 中添加 JMockit 依赖项
  1. <!-- https://mvnrepository.com/artifact/org.jmockit/jmockit --> <dependency> <groupId>org.jmockit</groupId> <artifactId>jmockit</artifactId> <version>1.49</version> <scope>test</scope> </dependency>
    在TestClass中模拟Class方法:
  1. public class TestClass{ @Test public void testMethod() { new MockUp<ClassName>(){ @Mock //mock the method here }; }

    }

  2. 按照
教程

了解更多关于如何使用JMockit。

© www.soinside.com 2019 - 2024. All rights reserved.