美文网首页springbootJavaWebspring boot
springboot 2 集成mybatis、单元测试、mock

springboot 2 集成mybatis、单元测试、mock

作者: 码道功臣 | 来源:发表于2019-02-19 17:53 被阅读20次

    介绍

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

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

    动手写代码

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

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

    图片.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

    相关文章

      网友评论

        本文标题:springboot 2 集成mybatis、单元测试、mock

        本文链接:https://www.haomeiwen.com/subject/iqrfyqtx.html