springboot 2 集成mybatis、單元測(cè)試、mock測(cè)試、測(cè)試數(shù)據(jù)回滾

介紹

這篇文章將介紹springboot2是如何集成mybatis的,并且提供完成的項(xiàng)目代碼。所以在文章里,不重要的地方就略過(guò)了。想了解詳情,可已clone項(xiàng)目自己看看。

https://github.com/bestaone/HiAuth 源碼從這里下載

動(dòng)手寫(xiě)代碼

創(chuàng)建maven項(xiàng)目order,目錄結(jié)構(gòu)如下

domain:存放數(shù)據(jù)模型、mapper:數(shù)據(jù)訪問(wèn)、service:服務(wù)層、controller:對(duì)外接口

圖片.png

pom.xml 添加mybatis依賴和分頁(yè)插件

<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>

添加數(shù)據(jù)模型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;
    
    ...
    
}

添加數(shù)據(jù)庫(kù)

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是數(shù)據(jù)庫(kù)關(guān)鍵字,所有表名使用orderx

編寫(xiě)mapper

mybatis的sql寫(xiě)在java文件和xml文件中都是可以的。

  • java文件的寫(xiě)法
@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文件的寫(xiě)法
<?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

#分頁(yè)插件配置
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 {
            //為了方面,零時(shí)這么寫(xiě)下
            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;

    //創(chuàng)建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,"數(shù)據(jù)不存");
        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);
    }

}

編輯單元測(cè)試測(cè)試service、mock測(cè)試Controller

  • 單元測(cè)試

@Transactional //支持?jǐn)?shù)據(jù)回滾,避免測(cè)試數(shù)據(jù)污染環(huán)境
@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測(cè)試
@WebAppConfiguration
@Transactional //支持?jǐn)?shù)據(jù)回滾,避免測(cè)試數(shù)據(jù)污染環(huán)境
@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("返回結(jié)果:{}", 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("返回結(jié)果:{}", 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("返回結(jié)果:{}", 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("返回結(jié)果:{}", 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("返回結(jié)果:{}", 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("返回結(jié)果:{}", 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("返回結(jié)果:{}", result);
    }

}

編譯、測(cè)試

cd Aiwan\aiwan-microsvr-order
mvn clean install
#等單元測(cè)試完成,大概1分鐘

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容