JUNIT5 + Mockito

本文介绍如何迁移至最新的JUnit5和Mockito3框架,包括Maven依赖的更新、单元测试示例和弃用PowerMock的建议,适合2023年后Java开发者

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

一、前言

二、Maven依赖

2.1 JUNIT5

2.2 Mockito3

2.3 surefire

三、UT示例

3.1 业务代码

3.2 单元测试

一、前言

JUnit和Mockito这两个单元测试框架在Java工程中被广泛应用。

但到2021年,仍有很多开发者在使用JUnit4+Mockito2+PowerMock,但不得不说,这套配置已经开始过时。

如今,JUnit5已经迭代到5.8.x,Mockito也进入了4.x阶段,开发者可以开始基于JUnit5+Mockito3来进行单测的开发。由于PowerMock在JUnit5上无法工作,所以不再使用PowerMock。Mockito3.4后,已经支持mock静态方法(Mockito (Mockito 3.5.10 API) (javadoc.io)),不引入PowerMock也能继续单测开发。

================================2023.04更新================================

Mockito已经更新至5.0,最低要求JDK11,带来了一些列新特性的支持与性能提升。PowerMock于2022年merge了一个支持Mockito4的PR(mockito 4.3.1 by sullis · Pull Request #1113 · powermock/powermock (github.com)),但截止2023.04,PowerMock仍然没有发布新的release版本。

如果应用基于JDK11,可以考虑使用Mockito5。

二、Maven依赖

2.1 JUNIT5

首先引入JUNIT5。

            <!-- junit5 -->
            <dependency>
                <groupId>org.junit.jupiter</groupId>
                <artifactId>junit-jupiter</artifactId>
                <version>5.8.2</version>
                <scope>test</scope>
            </dependency>

2.2 Mockito

2.2.1 Mockito3

除了引入mockito-core外,还需要引入mockito-jupiter扩展包。

其中mockito-inline是对Mockito的增强,包括mock final类 static方法。

            <!-- mockito3 -->
            <dependency>
                <groupId>org.mockito</groupId>
                <artifactId>mockito-core</artifactId>
                <version>3.12.4</version>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>org.mockito</groupId>
                <artifactId>mockito-inline</artifactId>
                <version>3.6.28</version>
                <scope>test</scope>
            </dependency>
            <!-- mockito for junit5 -->
            <dependency>
                <groupId>org.mockito</groupId>
                <artifactId>mockito-junit-jupiter</artifactId>
                <version>2.23.0</version>
                <scope>test</scope>
            </dependency>

2.2.2 Mockito5


            <!-- 5.0后无需引入mockito-inline -->
            <dependency>
                <groupId>org.mockito</groupId>
                <artifactId>mockito-core</artifactId>
                <version>5.2.0</version>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>org.mockito</groupId>
                <artifactId>mockito-junit-jupiter</artifactId>
                <version>5.2.0</version>
                <scope>test</scope>
            </dependency>

2.3 surefire

为了单测能正常运行并被mvn test识别,还需要更新maven-surefire-plugin,添加相关依赖。

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>3.0.0</version>
                <configuration>
                    <testFailureIgnore>true</testFailureIgnore>
                </configuration>
                <!-- 下面依赖视情况添加,如果单测可以运行则不需要加 -->
                <dependencies>
                    <dependency>
                        <groupId>org.junit.platform</groupId>
                        <artifactId>junit-platform-surefire-provider</artifactId>
                        <version>1.3.2</version>
                    </dependency>
                </dependencies>
            </plugin>

三、UT示例

业务代码:

@Service
public class DomainServiceImpl implements DomainService {

    @Resource
    private DataJpa dataJpa;

    @Override
    public Boolean foo(List<String> names) {
        int res = dataJpa.update(names);
        return res == 1;
    }
}

单元测试:

在JUNIT5中,不再提供@RunWith注解,需要使用@ExtendWith注解。

为了让Mockito正常工作,需要在@ExtendWith注解中使用MockitoExtension.class

同时,@Before被@BeforeAll或者@BeforeEach替换,若使用@BeforeAll,需要写在静态方法上。

@ExtendWith(MockitoExtension.class)
class DomainServiceImplTest {

    @InjectMocks
    private DomainServiceImpl domainService;

    @Mock
    private DataJpa dataJpa;

    @BeforeAll
    static void setUp() {
    }

    @Test
    void foo() {
        List<String> names = Lists.newArrayList("a", "b");
        Mockito.when(dataJpa.update(Mockito.anyList())).thenReturn(1);
        boolean res = domainService.foo(names);
        Assertions.assertTrue(res);
    }
}

静态方法Mock:

// code:
class Foo {
    public static String say() {
        return "hello";
    }
}

// ut:
Assertions.assertEquals("hello", Foo.say());
try (MockedStatic<Foo> mocked = Mockito.mockStatic(Foo.class)) {
    mocked.when(Foo::say).thenReturn("world");
    String res = Foo.say();
    Assertions.assertEquals("world", res);
}

// JDK11及以上版本中,try块中的变量可以在外部声明
MockedStatic<Foo> mocked = Mockito.mockStatic(Foo.class);
try (mocked) {
    mocked.when(Foo::say).thenReturn("world");
    String res = Foo.say();
    Assertions.assertEquals("world", res);
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值