SpringBoot 实战:JUnit5+MockMvc+Mockito 做好单元测试_springboot junit 5 mock

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

因为继承了`spring-boot-starter-parent`,所以我们依赖的`spring-boot-starter-test`不需要写具体的版本,可以直接集成父级的版本定义。其中,`spring-boot-starter-web`是用于提供 REST API 的 web 容器,`spring-boot-starter-test`可以提供各种测试框架的,`spring-boot-maven-plugin`是将 SpringBoot 应用打包为可执行 jar 的插件。


### 项目结构


因为是 DEMO 示例,我们实现一个 Echo 接口,能够接收请求参数,并返回加工后的字符串。按照惯例,我们使用万能的`Hello, World!`。


我们的项目结构如下:



├── pom.xml
└── src
├── main
│ ├── java
│ │ └── cn
│ │ └── howardliu
│ │ └── effective
│ │ └── spring
│ │ └── springbootjunit5mockio
│ │ ├── SpringbootJunit5MockioApplication.java
│ │ ├── controller
│ │ │ └── EchoController.java
│ │ └── service
│ │ ├── EchoService.java
│ │ └── impl
│ │ └── EchoServiceImpl.java
│ └── resources
│ └── application.yaml
└── test
└── java
└── cn
└── howardliu
└── effective
└── spring
└── springbootjunit5mockio
└── controller
├── EchoControllerMockTest.java
└── EchoControllerNoMockitoTest.java


* SpringbootJunit5MockioApplication:SpringBoot 应用启动入口
* EchoController:接口定义
* EchoService:实现业务逻辑接口
* EchoServiceImpl:接口实现
* EchoControllerMockTest:使用 Mock 代理 EchoService 实现
* EchoControllerNoMockitoTest:直接测试接口实现


#### EchoServiceImpl


我们看下`EchoService`的实现,这将是我们 DEMO 的核心实现:



@Service
public class EchoServiceImpl implements EchoService {
@Override
public String echo(String foo) {
return "Hello, " + foo;
}
}


#### EchoControllerNoMockitoTest


我们先使用 Junit5+MockMvc 实现 Controller 接口的普通调用,代码如下:



@SpringBootTest(classes = SpringbootJunit5MockioApplication.class)
@AutoConfigureMockMvc
class EchoControllerNoMockitoTest {
@Autowired
private MockMvc mockMvc;

@Test
void echo() throws Exception {
    final String result = mockMvc.perform(
            MockMvcRequestBuilders.get("/echo/")
                    .param("name", "看山")
    )
            .andExpect(MockMvcResultMatchers.status().isOk())
            .andDo(MockMvcResultHandlers.print())
            .andReturn()
            .getResponse()
            .getContentAsString(StandardCharsets.UTF_8);

    Assertions.assertEquals("Hello, 看山", result);
}

}


我们通过`SpringBootTest`注解定义这是一个 SpringBoot 应用的测试用例,然后通过`AutoConfigureMockMvc`启动测试容器。这样,就可以直接注入`MockMvc`实例测试 Controller 接口。


这里需要注意一点,网上很多教程会让写`@ExtendWith({SpringExtension.class})`这样一个注解,其实完全没有必要。通过源码我们可以知道,`SpringBootTest`注解已经添加了`ExtendWith`。


#### EchoControllerMockTest


这个测试用例中,我们通过 Mockito 组件代理`EchoService`的`echo`方法,代码如下:



@SpringBootTest(classes = SpringbootJunit5MockioApplication.class)
@ExtendWith(MockitoExtension.class)
@AutoConfigureMockMvc
class EchoControllerMockTest {
@Autowired
private MockMvc mockMvc;
@MockBean
private EchoService echoService;

@BeforeEach
void setUp() {
    Mockito.when(echoService.echo(Mockito.any()))
            .thenReturn("看山说:" + System.currentTimeMillis());
}

@Test
void echo() throws Exception {
    final String result = mockMvc.perform(
            MockMvcRequestBuilders.get("/echo/")
                    .param("name", "看山的小屋")
    )
            .andExpect(MockMvcResultMatchers.status().isOk())
            .andDo(MockMvcResultHandlers.print())
            .andReturn()
            .getResponse()
            .getContentAsString(StandardCharsets.UTF_8);

    Assertions.assertTrue(result.startsWith("看山"));
}

}


在这个示例中,我们需要注意`@ExtendWith(MockitoExtension.class)`注解,这个注解是用于引入`MockBean`的,我们通过对`echo`方法的拦截,使其返回我们定义好的响应结果。这种方式是为了在多系统或者多功能测试时,不需要真正调用接口。


比如,我们需要获取用户手机号,通常在接口中会校验用户有没有登录,我们就可以使用 Mockito 的能力代理登录验证,使结果永远是 true。


### 文末总结


至此,我们完成了 SpringBoot 集成 Junit5、MockMvc、Mockito 的示例。想要获取源码,只需要关注公众号「看山的小屋」,回复`spring`即可。


很多同学感觉单元测试没有编写的必要,直接使用 Swagger 或者 Postman 之类的工具就能很好的测试接口。确实如此,对于简单的 CRUD 接口,写单元测试的必要性不太高。但是,如果是复杂接口呢?接口参数有很多的组合,响应结果也需要各种验证,如果使用一次性的工具,每次测试组合参数就已经让人崩溃了,而且组合参数不能存留甚至不能在多人间传承,就会浪费很多的人力。


此时,单元测试的效果就会显现。我们只需要编写一次参数组合,放在 csv 之类的文件中,通过单元测试的参数化测试方式,即可多次运行,验证接口的正确性。


或者,当我们感觉系统已经臭味弥漫,对其重构之后,为了验证接口功能不变,也可以直接使用原来的测试用例加以验证。


综上,虽然测试用例编写麻烦,但是妙用无穷。


### 推荐阅读


![img](https://img-blog.csdnimg.cn/img_convert/d0bde38a5eccc2a77982be5251c83512.png)
![img](https://img-blog.csdnimg.cn/img_convert/bb2188a107c3affb28268f5da505678d.png)

**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化的资料的朋友,可以戳这里获取](https://bbs.csdn.net/topics/618608311)**

**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化的资料的朋友,可以戳这里获取](https://bbs.csdn.net/topics/618608311)**

**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值