springboot 2 集成mybatis、单元测试、mock测试、测试数据回滚

介绍

这篇文章将介绍springboot2是如何集成mybatis的,并且提供完成的项目代码。所以在文章里,不重要的地方就略过了。想了解详情,可已clone项目自己看看。

https://github.com/bestaone/Aiwan/tree/master/aiwan-microsvr-order 源码从这里下载

动手写代码

创建maven项目order,目录结构如下

domain:存放数据模型、mapper:数据访问、service:服务层、controller:对外接口

5458820-451226b2c79dac50.png
图片.png

pom.xml 添加mybatis依赖和分页插件

<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.0.0</version>
</dependency>
<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper-spring-boot-starter</artifactId>
    <version>1.2.10</version>
</dependency>

添加数据模型order

package com.bestaone.aiwan.order.domain;

public class Order {

    private Long id;
    private String no;
    private String title;
    private Float totalAmount;
    private OrderStatus status;
    private Date createTime;
    
    ...
    
}

添加数据库

DROP TABLE IF EXISTS `orderx`;
CREATE TABLE `orderx` (
  `id` bigint(11) NOT NULL,
  `no` varchar(50) DEFAULT NULL,
  `title` varchar(50) DEFAULT NULL,
  `totalAmount` decimal(19,5) DEFAULT NULL,
  `createTime` datetime DEFAULT NULL,
  `status` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

由于order是数据库关键字,所有表名使用orderx

编写mapper

mybatis的sql写在java文件和xml文件中都是可以的。

  • java文件的写法
@Mapper
public interface OrderMapper {

    @Insert("INSERT INTO orderx (id,no,title,totalAmount,createTime,status) VALUES (#{id},#{no},#{title},#{totalAmount},#{createTime},#{status})")
    void insert(Order user);

    @Delete("DELETE FROM orderx WHERE id = #{id}")
    void delete(Long id);

    @Update("UPDATE orderx SET no=#{no},title=#{title},totalAmount=#{totalAmount},createTime=#{createTime},status=#{status} WHERE id =#{id}")
    int update(Order user);

    @ResultMap("BaseResultMap")
    @Select("SELECT * FROM orderx WHERE id=#{id}")
    Order findById(Long id);

    @ResultMap("BaseResultMap")
    @Select("SELECT * FROM orderx")
    List<Order> findAll();

    @ResultMap("BaseResultMap")
    @Select("SELECT * FROM orderx WHERE status = #{status}")
    List<Order> findByStatus(OrderStatus status);

}
  • xml文件的写法
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.bestaone.aiwan.user.mapper.RoleMapper">

    <resultMap id="BaseResultMap" type="Role" >
        <id column="id" property="id" jdbcType="BIGINT" />
        <result column="code" property="code" jdbcType="VARCHAR" />
        <result column="name" property="name" jdbcType="VARCHAR" />
        <result column="description" property="description" jdbcType="VARCHAR" />
    </resultMap>

    <sql id="Base_Column_List" >
      id,name,description
    </sql>

    <select id="findByUserId" resultMap="BaseResultMap" >
        SELECT DISTINCT R.*
        FROM sys_role R
        LEFT JOIN sys_user_role UR ON UR.roleId=R.id
        WHERE UR.userId=#{userId}
    </select>

</mapper>

在application.properties中添加mybatis的配置

#扫描路径
mybatis.mapper-locations = classpath:mybatis/mapper/*.xml
#别名包路径
mybatis.type-aliases-package = com.bestaone.aiwan.order.domain

#分页插件配置
pagehelper.helperDialect = mysql
pagehelper.supportMethodsArguments = true
pagehelper.autoRuntimeDialect = true
pagehelper.offsetAsPageNum = true
pagehelper.rowBoundsWithCount = true
pagehelper.reasonable = false
pagehelper.returnPageInfo = true
pagehelper.params = count=countSql

添加service CRUD

@Service
public class OrderServiceImpl implements OrderService {

    @Resource
    OrderMapper mapper;

    @Override
    public Order save(Order order) {
        if(order.getId()!=null){
            mapper.update(order);
        } else {
            //为了方面,零时这么写下
            order.setId(System.currentTimeMillis());
            mapper.insert(order);
        }
        return order;
    }

    @Override
    public Order findById(Long id) {
        return mapper.findById(id);
    }

    @Override
    public List<Order> findAll() {
        return mapper.findAll();
    }

    @Override
    public void delete(Long id) {
        mapper.delete(id);
    }

    @Override
    public List<Order> findByStatus(OrderStatus status) {
        return mapper.findByStatus(status);
    }

}

添加Controller


@RestController
@RequestMapping("/api/order")
public class OrderController implements OrderApi {

    private Logger logger = LoggerFactory.getLogger(getClass());
    
    @Autowired
    OrderService userService;

    //创建order
    @Override
    @PostMapping
    public ApiResponse<String> create(@Valid @RequestBody OrderDto orderDto) throws CommonException {
        Assert.notNull(orderDto.getTitle(),50000, "title不存在");
        Assert.notNull(orderDto.getTotalAmount(),50000, "totalAmount不存在");
        Order order = new Order();
        order.setTitle(orderDto.getTitle());
        order.setTotalAmount(orderDto.getTotalAmount());
        order.setCreateTime(new Date());
        order.setStatus(OrderStatus.UNPAY);
        userService.save(order);
        return ApiResponse.sucess(order.getId().toString());
    }

    //跟新order
    @Override
    @PutMapping("/{id:\\d+}")
    public ApiResponse update(@PathVariable Long id, @Valid @RequestBody OrderDto orderDto, BindingResult errors) {
        Order order = userService.findById(id);
        order.setTitle(orderDto.getTitle());
        order.setTotalAmount(orderDto.getTotalAmount());
        order.setCreateTime(new Date());
        order.setStatus(OrderStatus.UNPAY);
        userService.save(order);
        return ApiResponse.sucess();
    }

    //删除order
    @Override
    @DeleteMapping("/{id:\\d+}")
    public ApiResponse delete(@PathVariable Long id) {
        userService.delete(id);
        return ApiResponse.sucess();
    }

    //查询order
    @Override
    @GetMapping
    public ApiResponse<PageVo<OrderVo>> query(Integer pageNum, Integer pageSize, String status) {
        Page pageinfo = PageHelper.startPage(pageNum, pageSize);
        List<Order> orders = userService.findByStatus(OrderStatus.valueOf(status));
        List<OrderVo> orderVos = new ArrayList<>();
        for(Order order : orders){
            OrderVo vo = new OrderVo();
            vo.setNo(order.getNo());
            vo.setTitle(order.getTitle());
            vo.setId(order.getId());
            vo.setStatus(order.getStatus()!=null?order.getStatus().name():null);
            vo.setTotalAmount(order.getTotalAmount());
            orderVos.add(vo);
        }
        return ApiResponse.sucess(new PageVo<>(pageinfo.getPageNum(), pageinfo.getPageSize(),pageinfo.getTotal(),pageinfo.getPages(),orderVos));
    }

    //获取详情
    @Override
    @GetMapping("/{id:\\d+}")
    public ApiResponse<OrderVo> getInfo(@PathVariable Long id) throws CommonException{
        Order order = userService.findById(id);
        Assert.notNull(order,20001,"数据不存");
        OrderVo vo = new OrderVo();
        vo.setNo(order.getNo());
        vo.setTitle(order.getTitle());
        vo.setId(order.getId());
        vo.setCreateTime(order.getCreateTime());
        vo.setStatus(order.getStatus()!=null?order.getStatus().name():null);
        vo.setTotalAmount(order.getTotalAmount());
        return ApiResponse.sucess(vo);
    }

}

编辑单元测试测试service、mock测试Controller

  • 单元测试

@Transactional //支持数据回滚,避免测试数据污染环境
@RunWith(SpringRunner.class)
@SpringBootTest(classes = OrderApplication.class)
public class OrderServiceTest {

    @Autowired
    public OrderService service;

    @Test
    public void CRUDTest() {

        //CREATE
        Order o = new Order();
        o.setTitle("test");
        o.setTotalAmount(1F);
        o.setCreateTime(new Date());
        o.setStatus(OrderStatus.UNPAY);
        o.setCreateTime(new Date());
        service.save(o);
        Assert.assertNotNull(o.getId());

        //READ
        o = service.findById(o.getId());
        Assert.assertNotNull(o.getId());

        //UPDATE
        o.setTitle("CRUDTest1");
        service.save(o);
        o = service.findById(o.getId());
        Assert.assertTrue(o.getTitle().equals("CRUDTest1"));
        
        //PAGE
        PageHelper.startPage(1,1);
        List<Order> list = service.findAll();
        PageInfo<Order> page = new PageInfo<>(list);
        Assert.assertTrue(page.getTotal()>0);
        
        //DELETE
        service.delete(o.getId());
        o = service.findById(o.getId());
        Assert.assertNull(o);

    }

}

  • mock测试
@WebAppConfiguration
@Transactional //支持数据回滚,避免测试数据污染环境
@RunWith(SpringRunner.class)
@SpringBootTest
public class OrderControllerTest {

    private Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    private WebApplicationContext wac;

    @Autowired
    private ObjectMapper objectMapper;

    private MockMvc mockMvc;

    @Before
    public void setup() {
        mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();
    }

    @Test
    public void whenQuerySuccess() throws Exception {
        String result = mockMvc.perform(
                get("/api/order")
                        .param("pageNum", "1")
                        .param("pageSize", "10")
                        .param("status", OrderStatus.PAID.name())
                .contentType(MediaType.APPLICATION_JSON_UTF8))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.code").value(10000))
                .andReturn().getResponse().getContentAsString();
        logger.debug("返回结果:{}", result);
    }

    @Test
    public void whenGetInfoSuccess() throws Exception {
        String result = mockMvc.perform(get("/api/order/1")
                .contentType(MediaType.APPLICATION_JSON_UTF8))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.code").value(10000))
                .andReturn().getResponse().getContentAsString();
        logger.debug("返回结果:{}", result);
    }

    @Test
    public void whenGetInfoFail() throws Exception {
        String result = mockMvc.perform(get("/api/order/a")
                .contentType(MediaType.APPLICATION_JSON_UTF8))
                .andExpect(status().is4xxClientError())
                .andReturn().getResponse().getContentAsString();
        logger.debug("返回结果:{}", result);
    }

    @Test
    public void whenCreateSuccess() throws Exception {
        OrderDto dto = new OrderDto().setTitle("iphone x 1").setTotalAmount(10001F);
        String result = mockMvc.perform(post("/api/order").contentType(MediaType.APPLICATION_JSON_UTF8)
                .content(objectMapper.writeValueAsString(dto)))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.code").value(10000))
                .andReturn().getResponse().getContentAsString();
        logger.debug("返回结果:{}", result);
    }

    @Test
    public void whenCreateFail() throws Exception {
        OrderDto dto = new OrderDto();
        String result = mockMvc.perform(post("/api/order").contentType(MediaType.APPLICATION_JSON_UTF8)
                .content(objectMapper.writeValueAsString(dto)))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.code").value(50000))
                .andReturn().getResponse().getContentAsString();
        logger.debug("返回结果:{}", result);
    }

    @Test
    public void whenUpdateSuccess() throws Exception {
        OrderDto dto = new OrderDto().setTitle("iphone x 2").setTotalAmount(10001F);
        String result = mockMvc.perform(put("/api/order/1").contentType(MediaType.APPLICATION_JSON_UTF8)
                .content(objectMapper.writeValueAsString(dto)))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.code").value(10000))
                .andReturn().getResponse().getContentAsString();
        logger.debug("返回结果:{}", result);
    }

    @Test
    public void whenDeleteSuccess() throws Exception {
        String result = mockMvc.perform(delete("/api/order/1")
                .contentType(MediaType.APPLICATION_JSON_UTF8))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.code").value(10000))
                .andReturn().getResponse().getContentAsString();
        logger.debug("返回结果:{}", result);
    }

}

编译、测试

cd Aiwan\aiwan-microsvr-order
mvn clean install
#等单元测试完成,大概1分钟

本文源码 https://github.com/bestaone/Aiwan/tree/master/aiwan-microsvr-order

猜你喜欢

转载自blog.csdn.net/weixin_34293141/article/details/88194651