Java单元测试及常用语句

java,单元测试,常用,语句 · 浏览次数 : 110

小编点评

```java import org.junit.Assert; import org.junit.Mock; import org.junit.runner.RunWith; import org.powermock.PowerMock; import org.powermock.core.PowerMockAnnotations; import org.powermock.api.mockito2.MockitoAnnotations; import org.powermock.modules.junit4.PowerMockRunner; @RunWith(PowerMockRunner.class) @PrepareForTest({OrderTypeEnum.class, OrderServiceImpl.class}) public class OrderServiceImplTest { @Mock private OrderService orderService; @Mock private OrderInfo orderInfoDTO; @Before public void setUp() { MockitoAnnotations.initMocks(this); } @Test public void testGetOrderInfo() { // mock dependencies orderService.getOrderInfo(orderInfoDTO); // assert expectations Assert.assertEquals("123", orderInfoDTO.getOrderNumber()); } @Test public void testInvalidOrderType() { // mock dependencies orderService.getOrderInfo(new OrderInfoDTO()); // assert expectations Assert.assertEquals("Invalid order type", orderInfoDTO.getOrderType()); } } ``` **代码解释:** * **@Mock** 注解用于模拟接口或依赖对象。 * **@PrepareForTest** 注解用于配置测试场景,包括模拟类和依赖对象。 * **MockitoAnnotations.initMocks** 方法用于初始化模拟对象。 * **@Test** 方法用于执行测试用例。 * **verify** 方法用于检查接口是否被调用了。 * **assert** 方法用于检查返回值是否等于预期值。 * **@Test(expected = BPLException.class)** 注解用于测试当接口返回值为空时抛出的异常类型。 **注意:** * 代码中的测试场景仅展示了获取订单信息和抛出异常两种情况。 * 可以根据需求添加更多测试用例。

正文

1 前言

编写Java单元测试用例,即把一段复杂的代码拆解成一系列简单的单元测试用例,并且无需启动服务,在短时间内测试代码中的处理逻辑。写好Java单元测试用例,其实就是把“复杂问题简单化,建单问题深入化“。在编写的过程中, 我们也可以对自己的代码进行一个二次检查。

以下是我总结的一些编写单元测试的好处:

1.测试代码逻辑时,不需要启动整个应用。

2.单元测试可以覆盖边界值

3.提高原有代码的复用

4.可以有效避免代码改动后,对原有逻辑的潜在影响

2 准备环境

Mockito是目前最普遍的单元测试模拟框架。Mockito可以模拟应用中依赖的复杂对象,从而把测试对象和依赖对象隔离开。PowerMock为Mockito提供了扩展功能。为模拟静态方法,final类,和私有方法等。我们选择使用以Mockito为主,PowerMock为辅的框架来做单元测试。

2.1 引入Mockito和PowerMock包,在pom.xml文件中加入以下依赖:

<properties>
    <powermock.version>2.0.9</powermock.version>
</properties>
<dependency>
    <groupId>org.powermock</groupId>
    <artifactId>powermock-core</artifactId>
    <version>${powermock.version}</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.powermock</groupId>
    <artifactId>powermock-api-mockito2</artifactId>
    <version>${powermock.version}</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.powermock</groupId>
    <artifactId>powermock-module-junit4</artifactId>
    <version>${powermock.version}</version>
    <scope>test</scope>

PowerMock目前最新版本为2.0.9【PowerMock链接】由于PowerMock包中已经包含了对应的Mockito和JUnit包,所以无需再单独引入。

3 一些常用的mock语句

3.1 模拟指定类的对象实例,用于模拟依赖对象(类成员)

在Spring中,这些成员对象通过@Autowire,@Resource,@Value等方式注入,可能涉及到环境配置或者依赖第三方接口。在单元测试中,不是我们关注的点,所以可以用mock模拟

//方法一
Mockito.mock(OrderInfo.class);
//方法二
@Mock
private OrderInfo orderInfo;


@Before
public void setUp(){
MockitoAnnotations.initMocks(this);
}

3.2 定义被测试对象

把被测试服务类进行实例化

@InjectMocks
private OrderServiceImpl orderService;

3.3 模拟枚举类型/静态方法

需要把对应的模拟类放在@PrepareForTest中

//必须添加@RunWith和@PrepareForTest在类前
@RunWith(PowerMockRunner.class)
@PrepareForTest(OrderTypeEnum.class)


//在@Before中添加枚举mock
@Before
public void beforeTest() {
    mockStatic(OrderTypeEnum.class);
}

3.4 模拟依赖方法

在模拟完依赖的参数和返回值后,可以利用Mockito功能,进行依赖方法的模拟。如果模拟对象还有方法调用,则需要模拟这些依赖对象的方法。

/***
when.thenReturn 和 doReturn.when是两种实现方式
只有在使用@Spy时才会有区别
参考链接:https://www.imooc.com/wenda/detail/594190#id_653606
***/


//模拟枚举的方法调用
when(OrderTypeEnum.getByValue(anyInt())).thenReturn(100);
//模拟依赖对象的依赖方法调用
doReturn(resultInfoDTO).when(orderInfoService).getLastOrderInfo(orderInfoDTO);

3.5 模拟构造方法

PowerMock提供了对构造方法的模拟,但是需要把构造方法的类放在@PrepareForTest中

//必须在@PrepareForTest中添加对应类
@PrepareForTest({OrderTypeEnum.class, OrderServiceImpl.class})
whenNew(OrderInfoDTO.class).withNoArguments().thenReturn(orderInfoDTO);

3.6 验证方法调用次数

被测方法调用后,一些方法会出现调用多次或根据不同条件进行不同次数的调用。此时,可以根据验证方法调用次数,确定代码的有效性

verify(orderInfoService,times(1)).getLastOrderInfo(orderInfoDTO);

3.7 验证返回值

对于方法调用后的出参,我们会有一定的预期。所以,可以根据校验返回值是否符合预期,确保返回值的正确性

Assert.assertEquals(result, "123");

3.8 验证异常对象

JUnit的@Test注解提供了一个expected属性,可以指定一个期望的异常类型,用于捕获异常并验证其异常类型。【注】:只能验证异常类型,不能验证异常信息。

@Test(expected = BPLException.class)

4 单测举例

下面是一个本地方法的单元测试用例,方法中调用了外部接口,并且其中包含了枚举值的使用。

源方法即需要单测方法:

首先,是单元测试时一些必要的初始化

4.1 单测场景一(确定接口调用,并返回值正确):

通过verify方法来确定接口是否调用过,并且只调用过1次。

通过assert来确认返回值是否满足预期

4.2 单测场景二(必要异常是否抛出):

通过在@Test注解上加入expected属性,测试当接口返回值为空时,是否可以抛出异常

4 总结

编写单元测试在开发中的地位举足轻重。在开发过程中,避免不了优化或重构历史代码。单元测试,在一定程度上可以帮助测试更新后逻辑,以及潜在调用链。另外也分享一些链接,希望可以帮助大家完成从0到1的搭建。

5 参考资料

作者:京东物流 牟佳义

来源:京东云开发者社区 自猿其说Tech 转载请注明来源

与Java单元测试及常用语句相似的内容:

Java单元测试及常用语句

编写Java单元测试用例,即把一段复杂的代码拆解成一系列简单的单元测试用例,并且无需启动服务,在短时间内测试代码中的处理逻辑。写好Java单元测试用例,其实就是把“复杂问题简单化,建单问题深入化“。在编写的过程中, 我们也可以对自己的代码进行一个二次检查。

Java单元测试浅析(JUnit+Mockito)

单元测试是阶段性测试的首要环节,也是白盒测试的一种,该内容的编写与实践可以前置在研发完成,研发在编写业务代码的时候就需要生成对应代码的单元测试。本篇文章介绍了什么是单元测试、为什么要单元测试、单元测试的框架以及单元测试的工具。

一台不容错过的Java单元测试代码“永动机”

如何将失误降到最低?我们期望能打造一台生产Java单元测试代码的“永动机”,源源不断地为开发者生产代码,辅助大家高效地做好单元测试,节省精力能投入到更多的业务创新中去。

Java SpringBoot Test 单元测试中包括多线程时,没跑完就结束了

如何阻止 Java SpringBoot Test 单元测试中包括多线程时,没跑完就结束了 使用 CountDownLatch CountDownLatch、CyclicBarrier 使用区别 多线程 ThreadPoolTaskExecutor 应用 Java BasePooledObjectF

[Java]线程生命周期与线程通信

出于个人知识掌握程度与时间成本等多方面整体考虑,本篇文章对线程生命周期与线程通信的阐述并非非常详细,故可能并不适合所有博友,一些知识点在文中给出的【启发博文】中可能更容易找到答案。 如果文中阐述有不妥或不对的,多多交流。

java代码审计-某酒店管理系统

java代码审计-某酒店后台管理系统 目录java代码审计-某酒店后台管理系统1、简介2、文件上传漏洞3、CSRF漏洞4、存储型XSS 1、简介 文章只作研究学习,请勿非法渗透测试; 该系统是使用SpringMVC+Mysql搭建开发的一套中小型企业酒店后台管理系统; 这里只对源代码进行审计,第三方

Java变量自增表达式 i = i++ 的底层逻辑(简述)

Java变量自增表达式 i = i++ 的底层逻辑(简述) 前言 很多老师告诉我们,i = i++ 的运算过程是 temp = i; i ++; i = temp; 所以i的值不变。但我总觉得这个temp的出现有些莫名其妙。所以在网上检索之后,把大佬们的解释做了一点总结和简化,权当拾人牙慧。 要搞懂

Java面试题:线程池内“闹情绪”的线程,怎么办?

在Java中,线程池中工作线程出现异常的时候,默认会把异常往外抛,同时这个工作线程会因为异常而销毁,我们需要自己去处理对应的异常,异常处理的方法有几种:在传递的任务中去处理异常,对于每个提交到线程池中的执行的任务,可以提前通过异常进行捕获,这样即便出现了异常,也不会影响线程池中的工作线程,使用Fut...

Java面试题:如果你这样做,你会后悔的,两次启动同一个线程~~~

当一个线程被启动后,如果再次调start()方法,将会抛出IllegalThreadStateException异常。 这是因为Java线程的生命周期只有一次。调用start()方法会导致系统在新线程中运行执行体,但是如果线程已经结束,则不能再次使用,需要重新创建一个新的线程对象并调用start()...

字节面试:说说Java中的锁机制?

Java 中的锁(Locking)机制主要是为了解决多线程环境下,对共享资源并发访问时的同步和互斥控制,以确保共享资源的安全访问。 锁的作用主要体现在以下几个方面: 互斥访问:确保在任何时刻,只有一个线程能够访问特定的资源或执行特定的代码段。这防止了多个线程同时修改同一资源导致的数据不一致问题。 内