前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Spring单元测试

Spring单元测试

作者头像
李鸿坤
发布2020-11-03 14:45:30
1.1K0
发布2020-11-03 14:45:30
举报
文章被收录于专栏:泛泛聊后端泛泛聊后端

单元测试对开发来说是一种基本素养。Java这方面的工业标准是使用JUnit。在使用了Spring框架及其衍生的相关框架后,会有不同程度的变化。

最基础的用法即使用Spring容器的相关功能,即使这样也需要使用到Spring单元测试相关的支持。

代码语言:javascript
复制
<dependencies>
  <dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.13</version>
    <scope>test</scope>
  </dependency>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    <scope>test</scope>
  </dependency>
</dependencies>

<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-framework-bom</artifactId>
      <version>5.2.6.RELEASE</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
  </dependencies>
</dependencyManagement>

首先需要引入junit和Spring-test包。然后编写单元测试类。

代码语言:javascript
复制
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:lifecycle.xml"})
public class LifeCycleTest {

    @Autowired
    private ApplicationContext applicationContext;

    @Test
    public void test(){
        applicationContext.getBean("lifeCycleBean");
    }
}

使用RunWith注解去指定单元测试使用SpringJUnit4ClassRunner来启动。ContextConfiguration注解指定了ApplicationContext的bean定义文件。其他的操作跟 JUnit 没什么区别了,实现单元测试方法,然后方法加上Test注解即可每个方法进行测试用例的执行。

Spring Boot 单元测试

越来越多的应用并不会直接裸用Spring进行开发,而是使用Spring Boot。对于单元测试,它也对其进行了一些简化。

代码语言:javascript
复制
<dependencies>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
  </dependency>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
  </dependency>
  <dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.13</version>
    <scope>test</scope>
  </dependency>
</dependencies>

同样需要引入对应的依赖,分别是junit 和 spring-boot-starter-test ,这里要对Controller进行测试需要引入依赖和编写对应的代码。

代码语言:javascript
复制
//HelloController.java

@RestController
public class HelloController {

    @RequestMapping("/hello")
    public String hello(){
        return "hello mvc mock";
    }
}

//Application.java
@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class,args);
    }
}

需要单元测试的代码如上,这是一个MVC的应用,需要使用到MvcMock。

代码语言:javascript
复制
@RunWith(SpringRunner.class)
@SpringBootTest
public class HelloControllerTest {

    @Autowired
    private WebApplicationContext context;

    private MockMvc mockMvc;

    @Before
    public void init() {
        mockMvc = MockMvcBuilders.webAppContextSetup(context).build();
    }

    @Test
    public void testHello() throws Exception {
        MvcResult mvcResult = mockMvc.perform(MockMvcRequestBuilders.get("/hello").content(""))
                .andExpect(MockMvcResultMatchers.status().isOk())
                .andDo(MockMvcResultHandlers.print())
                .andReturn();
        System.out.println(mvcResult.getResponse().getContentAsString());
    }
}

SpringBootTest 注解会直接找到对应的Spring Boot 启动类,在单元测试的时候进行启动。而MockMvc是直接通过网络对启动的应用程序进行模拟请求。MockMvcRequestBuilders可以很方便地进行参数或者HTTP协议相关的配置。

对于MvcMock可能会是否有必要学习和使用的疑问,比如在实际的生产过程中使用的OpenAPI,或者自己手动整理的CURL往往能够更加通用。但是单元测试是跟随着编译过程的,能够提早发现问题。他们在软件开发的不同生命周期中。

Mockito

很多应用不会独立存在,它需要跟外部进行交互。这样的应用单元测试如果要完完整整跑下来,则需要数据库、第三方接口。这些都是不确定的因素,比如第三方接口并不一定会如你的预期,或者数据库的脏数据等等。都可能导致你的单元测试崩溃。

最好的方式就是让你的单元测试程序跟外部依赖解耦。这时候就需要Mock了,在单元测试中如果遇到外部依赖,则给自己返回恰当的值。

引入依赖包

代码语言:javascript
复制
<dependency>
  <groupId>org.mockito</groupId>
  <artifactId>mockito-core</artifactId>
  <version>3.5.15</version>
  <scope>test</scope>
</dependency>

编写的测试代码如下

代码语言:javascript
复制
@RunWith(JUnit4.class)
public class MockitoTest {

    @Test
    public void test(){
        //You can mock concrete classes, not just interfaces
        LinkedList mockedList = mock(LinkedList.class);

        //stubbing
        when(mockedList.get(0)).thenReturn("first");
        when(mockedList.get(1)).thenThrow(new RuntimeException());

        //following prints "first"
        System.out.println(mockedList.get(0));

        //following prints "null" because get(999) was not stubbed
        System.out.println(mockedList.get(999));

        //following throws runtime exception
        System.out.println(mockedList.get(1));
    }
}

mock 用来包装一个返回,这里可以是一个接口的方法调用或者其他。上述是模拟返回一个LinkedList,并对其返回进行定义,然后进行测试。运行结果如下

代码语言:javascript
复制
first
null

java.lang.RuntimeException
....

when...thenReturn 和 when...thenThrow 分别定义的mockList的行为,执行结果与定义的一致。

官方文档 http://www.javadoc.io/doc/org.mockito/mockito-core/2.8.47/org/mockito/Mockito.html

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-10-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 泛泛聊后端 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Spring Boot 单元测试
  • Mockito
相关产品与服务
数据库
云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档