spring-boot-单元测试

Posted 技术改变生活

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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

以上是关于spring-boot-单元测试的主要内容,如果未能解决你的问题,请参考以下文章

spring-boot 单元测试获取应用程序属性

基于spring-boot的应用程序的单元+集成测试方案

spring-boot2.0 单元测试JUnit4

Spring-Boot 单元测试:ConstraintValidator 中的@Value

spring-boot-单元测试

spring-boot学习写一个简单的单元测试