spring-boot-单元测试

pom依赖

    <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>2.3.1</version>
        </dependency>

快捷键

ctrl + shift + t

service层 测试


@RunWith(SpringRunner.class)
@SpringBootTest
public class LearnServiceTest {

    @Autowired
    private LearnService learnService;

    @Test
    public void getLearn() {
        LearnResource learnResource = learnService.selectByKey(1001L);
        Assert.assertThat(learnResource.getAuthor(), is("嘟嘟MD独立博客"));
    }

    /**
     * 这样测试完数据就会回滚了,不会造成垃圾数据
     * <p>
     *
     * @Transactional :单元个测试的时候如果不想造成垃圾数据,可以开启事物功能,记在方法或者类头部添加
     * <p>
     * @Rollback(false): @Rollback 表示事务执行完回滚,支持传入一个参数value,默认true 即回滚,false不回滚。
     */
    @Test
    @Transactional
//    @Rollback(false)
    public void add() {
        LearnResource bean = new LearnResource();
        bean.setAuthor("测试回滚");
        bean.setTitle("回滚用例");
        bean.setUrl("http://tengj.top");
        learnService.save(bean);
    }

}

controller 测试

@RunWith(SpringRunner.class)
@SpringBootTest
public class LearnControllerTest {

    @Autowired
    private WebApplicationContext wac;

    private MockMvc mvc;

    private MockHttpSession session;

    @Before
    public void setupMockMvc() {
        //初始化MockMvc对象
        mvc = MockMvcBuilders.webAppContextSetup(wac).build();

        //构建session
        session = new MockHttpSession();
        User user = new User("root", "root");
        //拦截器那边会判断用户是否登录,所以这里注入一个用户
        session.setAttribute("user", user);
    }

    /**
     * 新增教程测试用例
     * <p>
     * post 请求
     *
     * @throws Exception
     */
    @Test
    public void addLearn() throws Exception {
        // 手动写 json
        //String json = "{\"author\":\"HAHAHAA\",\"title\":\"Spring\",\"url\":\"http://tengj.top/\"}";

        // 前端传递的 json 格式,对象 转 json
        LearnResource learnResource = new LearnResource();
        learnResource.setAuthor("HAHAHAAs");
        learnResource.setTitle("Spring");
        learnResource.setUrl("http://tengj.top/");

        Gson gson = new Gson();
        String json = gson.toJson(learnResource);

        //mockMvc.perform执行一个请求
        //MockMvcRequestBuilders构造一个请求
        mvc.perform(MockMvcRequestBuilders.post("/learn/add")
                //发送的数据格式
                .accept(MediaType.APPLICATION_JSON_UTF8)
                //传json参数 通过 @RequestBody注解 接受的参数
                .content(json.getBytes())
                // 注入一个session
                .session(session)
        )
                //andExpect添加执行完成后的断言
                .andExpect(MockMvcResultMatchers.status().isOk())
                //andDo添加一个结果处理器,表示要对结果做点什么事情
                .andDo(MockMvcResultHandlers.print());//输出整个响应结果信息
    }

    /**
     * 获取教程测试用例
     * <p>
     * get 请求
     *
     * @throws Exception
     */
    @Test
    public void qryLearn() throws Exception {
        mvc.perform(MockMvcRequestBuilders.get("/learn/resource/1001")
                .contentType(MediaType.APPLICATION_JSON_UTF8)
                .accept(MediaType.APPLICATION_JSON_UTF8)
                .session(session)
        )
                .andExpect(MockMvcResultMatchers.status().isOk())
                //jsonPath用来获取author字段比对是否为嘟嘟MD独立博客,不是就测试不通过
                .andExpect(MockMvcResultMatchers.jsonPath("$.author").value("嘟嘟MD独立博客"))
                .andExpect(MockMvcResultMatchers.jsonPath("$.title").value("Spring Boot干货系列"))
                .andDo(MockMvcResultHandlers.print());
    }

    /**
     * 修改教程测试用例
     *
     * @throws Exception
     */
    @Test
    public void updateLearn() throws Exception {
        String json = "{\"author\":\"测试修改\",\"id\":1031,\"title\":\"Spring Boot干货系列\",\"url\":\"http://tengj.top/\"}";
        mvc.perform(MockMvcRequestBuilders.post("/learn/update")
                .accept(MediaType.APPLICATION_JSON_UTF8)
                .content(json.getBytes())//传json参数
                .session(session)
        )
                .andExpect(MockMvcResultMatchers.status().isOk())
                .andDo(MockMvcResultHandlers.print());
    }

    /**
     * 删除教程测试用例
     *
     * @throws Exception
     */
    @Test
    public void deleteLearn() throws Exception {
        String json = "[1031]";
        mvc.perform(MockMvcRequestBuilders.post("/learn/delete")
                .accept(MediaType.APPLICATION_JSON_UTF8)
                .content(json.getBytes())//传json参数
                .session(session)
        )
                .andExpect(MockMvcResultMatchers.status().isOk())
                .andDo(MockMvcResultHandlers.print());
    }

}

单元测试事物没有回滚

1.查看MySQL当前默认的存储引擎:

mysql> show variables like '%storage_engine%';
  1. user表用了什么引擎
mysql> show create table user;
  1. 将user表修为InnoDB存储引擎
mysql> ALTER TABLE user ENGINE=INNODB;

断言 Assert.assertThat使用

assertThat( [value], [matcher statement] );

//value 是接下来想要测试的变量值;
//matcher statement 是使用 Hamcrest 匹配符来表达的对前面变量所期望的值的声明
//如果 value 值与 matcher statement 所表达的期望值相符,则测试成功,否则测试失败。
// 想判断某个字符串 s 是否含有子字符串 "developer" 或 "Works" 中间的一个
assertThat(s, anyOf(containsString("developer"), containsString("Works")));
// 匹配符 anyOf 表示任何一个条件满足则成立,类似于逻辑或 "||", 匹配符 containsString 表示是否含有参数子 

// 联合匹配符not和equalTo表示“不等于”
assertThat( something, not( equalTo( "developer" ) ) );
// 联合匹配符not和containsString表示“不包含子字符串”
assertThat( something, not( containsString( "Works" ) ) );
// 联合匹配符anyOf和containsString表示“包含任何一个子字符串”
assertThat(something, anyOf(containsString("developer"), containsString("Works")));

字符相关匹配符
/**
* equalTo匹配符断言被测的testedValue等于expectedValue,
* equalTo可以断言数值之间,字符串之间和对象之间是否相等,相当于Object的equals方法
*/
assertThat(testedValue, equalTo(expectedValue));

/**equalToIgnoringCase匹配符断言被测的字符串testedString
*在忽略大小写的情况下等于expectedString
*/
assertThat(testedString, equalToIgnoringCase(expectedString));

/**equalToIgnoringWhiteSpace匹配符断言被测的字符串testedString
*在忽略头尾的任意个空格的情况下等于expectedString,
*注意:字符串中的空格不能被忽略
*/
assertThat(testedString, equalToIgnoringWhiteSpace(expectedString);

/**containsString匹配符断言被测的字符串testedString包含子字符串subString**/
assertThat(testedString, containsString(subString) );

/**endsWith匹配符断言被测的字符串testedString以子字符串suffix结尾*/
assertThat(testedString, endsWith(suffix));

/**startsWith匹配符断言被测的字符串testedString以子字符串prefix开始*/
assertThat(testedString, startsWith(prefix));

一般匹配符
/**nullValue()匹配符断言被测object的值为null*/
assertThat(object,nullValue());

/**notNullValue()匹配符断言被测object的值不为null*/
assertThat(object,notNullValue());

/**is匹配符断言被测的object等于后面给出匹配表达式*/
assertThat(testedString, is(equalTo(expectedValue)));

/**is匹配符简写应用之一,is(equalTo(x))的简写,断言testedValue等于expectedValue*/
assertThat(testedValue, is(expectedValue));

/**is匹配符简写应用之二,is(instanceOf(SomeClass.class))的简写,
*断言testedObject为Cheddar的实例
*/
assertThat(testedObject, is(Cheddar.class));

/**not匹配符和is匹配符正好相反,断言被测的object不等于后面给出的object*/
assertThat(testedString, not(expectedString));

/**allOf匹配符断言符合所有条件,相当于“与”(&&)*/
assertThat(testedNumber, allOf( greaterThan(8), lessThan(16) ) );

/**anyOf匹配符断言符合条件之一,相当于“或”(||)*/
assertThat(testedNumber, anyOf( greaterThan(16), lessThan(8) ) );

数值相关匹配符
/**closeTo匹配符断言被测的浮点型数testedDouble在20.0?à0.5范围之内*/
assertThat(testedDouble, closeTo( 20.0, 0.5 ));

/**greaterThan匹配符断言被测的数值testedNumber大于16.0*/
assertThat(testedNumber, greaterThan(16.0));

/** lessThan匹配符断言被测的数值testedNumber小于16.0*/
assertThat(testedNumber, lessThan (16.0));

/** greaterThanOrEqualTo匹配符断言被测的数值testedNumber大于等于16.0*/
assertThat(testedNumber, greaterThanOrEqualTo (16.0));

/** lessThanOrEqualTo匹配符断言被测的testedNumber小于等于16.0*/
assertThat(testedNumber, lessThanOrEqualTo (16.0));

集合相关匹配符
/**hasEntry匹配符断言被测的Map对象mapObject含有一个键值为"key"对应元素值为"value"的Entry项*/
assertThat(mapObject, hasEntry("key", "value" ) );

/**hasItem匹配符表明被测的迭代对象iterableObject含有元素element项则测试通过*/
assertThat(iterableObject, hasItem (element));

/** hasKey匹配符断言被测的Map对象mapObject含有键值“key”*/
assertThat(mapObject, hasKey ("key"));

/** hasValue匹配符断言被测的Map对象mapObject含有元素值value*/
assertThat(mapObject, hasValue(value));

Junit基本注解介绍

@BeforeClass 在所有测试方法前执行一次,一般在其中写上整体初始化的代码

@AfterClass 在所有测试方法后执行一次,一般在其中写上销毁和释放资源的代码

@Before 在每个测试方法前执行,一般用来初始化方法(比如我们在测试别的方法时,类中与其他测试方法共享的值已经被改变,为了保证测试结果的有效性,我们会在@Before注解的方法中重置数据)

@After 在每个测试方法后执行,在方法执行完成后要做的事情

@Test(timeout = 1000) 测试方法执行超过1000毫秒后算超时,测试将失败

@Test(expected = Exception.class) 测试方法期望得到的异常类,如果方法执行没有抛出指定的异常,则测试失败

@Ignore(“not ready yet”) 执行测试时将忽略掉此方法,如果用于修饰类,则忽略整个类

@Test 编写一般测试用例

@RunWith 在JUnit中有很多个Runner,他们负责调用你的测试代码,每一个Runner都有各自的特殊功能,你要根据需要选择不同的Runner来运行你的测试代码。

打包测试

我们用一个类,把所有的测试类整理进去,然后直接运行这个类,所有的测试类都会执行

@RunWith(Suite.class)
@Suite.SuiteClasses(LearnServiceTest.class)
public class SuitsTest {
}

参考:
原文: http://tengj.top/2017/12/28/springboot12/  
作者: 嘟嘟MD

作者:痴乙
来源:CSDN
原文:https://blog.csdn.net/fxbin123/article/details/80617754

原文地址:https://www.cnblogs.com/zhangjianbin/p/10082366.html

时间: 12-07

spring-boot-单元测试的相关文章

Spring Boot的单元测试(Unit Test)

最近做了一些Spring Boot单元测试方面的东西,总结一下. 单元测试尽量要和Spring Boot框架减少耦合度,当你在测试某一项功能点是需要mock太多的对象时你就应该意识到这个功能点的耦合度太高了 使用Constructor Injection,不要使用Field Injection.这样才能更容易写单元测试代码.在Spring Framework 4.3以后,如果你只有一个Constructor, 就不再需要写@Autowired,Spring会默认他是autowire目标: pub

Spring Boot的单元测试(Unit Test)(一)

最近做了一些Spring Boot单元测试方面的东西,总结一下. 单元测试尽量要和Spring Boot框架减少耦合度,当你在测试某一项功能点是需要mock太多的对象时你就应该意识到这个功能点的耦合度太高了 使用Constructor Injection,不要使用Field Injection.这样才能更容易写单元测试代码.在Spring Framework 4.3以后,如果你只有一个Constructor, 就不再需要写@Autowired,Spring会默认他是autowire目标: pub

spring boot?Swagger2文档构建及单元测试

首先,回顾并详细说明一下在快速入门中使用的@Controller.@RestController.@RequestMapping注解.如果您对Spring MVC不熟悉并且还没有尝试过快速入门案例,建议先看一下快速入门的内容. @Controller:修饰class,用来创建处理http请求的对象 @RestController:Spring4之后加入的注解,原来在@Controller中返回json需要@ResponseBody来配合,如果直接用@RestController替代@Contro

Spring boot 1.4.2 单元测试配置

新版较旧版简化了很多 直接在测试类上添加 @RunWith(SpringRunner.class) @SpringBootTest(classes = 自己的启动类, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) 同事注入 TestRestTemplate类 和通过 @LocalServerPort注解注入当前的端口号 具体测试代码如下: @RunWith(SpringRunner.class) @SpringBootTe

Spring Boot开发之流水无情(二)

上篇散仙写了一个很简单的入门级的Spring Boot的例子,没啥技术含量,不过,其实学任何东西只要找到第一个突破口,接下来的事情就好办了,人最怕什么? 我想莫过于干一件事情,没有下手的地方了,而当你一旦找到了这感觉,就可以很喜悦的顺藤摸瓜般的探索你强烈想探索求知的某种事物了,这种冥冥之中玄而又玄的感觉是什么?回想一下: (1) 当你把第一个某种编程语言的Hello World的例子,成功的运行在一个IDE中  (2) 当你第一次从老家出发到达了某个你从未涉足过的地方  (3) 当你成功的完成了

Spring Boot? 配置文件详解:自定义属性、随机数、多环境配置等

自定义属性与加载 我们在使用Spring Boot的时候,通常也需要定义一些自己使用的属性,我们可以如下方式直接定义: application-dev.yml com.didispace.blog: name: 程序猿DD title: Spring Boot教程 desc: ${com.didispace.blog.name}正在努力写<${com.didispace.blog.title}> # 随机字符串 value: ${random.value} # 随机int number: ${

3.Spring Boot中使用Swagger2构建强大的RESTful API文档

原文:http://www.jianshu.com/p/8033ef83a8ed 由于Spring Boot能够快速开发.便捷部署等特性,相信有很大一部分Spring Boot的用户会用来构建RESTful API.而我们构建RESTful API的目的通常都是由于多终端的原因,这些终端会共用很多底层业务逻辑,因此我们会抽象出这样一层来同时服务于多个移动端或者Web前端. 这样一来,我们的RESTful API就有可能要面对多个开发人员或多个开发团队:IOS开发.Android开发或是Web开发

Spring Boot属性配置文件详解

自定义属性与加载 我们在使用Spring Boot的时候,通常也需要定义一些自己使用的属性,我们可以如下方式直接定义: com.example.blog.name=zzh com.example.blog.title=hello springboot @Component public class BlogProperties { @Value("${com.example.blog.name}") private String name; @Value("${com.exa

spring-boot实战【10】【转】:Spring Boot中使用@Async实现异步调用

什么是"异步调用"? "异步调用"对应的是"同步调用",同步调用指程序按照定义顺序依次执行,每一行程序都必须等待上一行程序执行完成之后才能执行:异步调用指程序在顺序执行时,不等待异步调用的语句返回结果就执行后面的程序. 同步调用 下面通过一个简单示例来直观的理解什么是同步调用: 定义Task类,创建三个处理函数分别模拟三个执行任务的操作,操作消耗时间随机取(10秒内) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16

spring-boot实战【12】:Spring Boot中使用JavaMailSender发送邮件

相信使用过Spring的众多开发者都知道Spring提供了非常好用的JavaMailSender接口实现邮件发送.在Spring Boot的Starter模块中也为此提供了自动化配置.下面通过实例看看如何在Spring Boot中使用JavaMailSender发送邮件. 快速入门 在Spring Boot的工程中的pom.xml中引入spring-boot-starter-mail依赖: 1 2 3 4 <dependency> <groupId>org.springframew