1.我要添加一条用户数据
现在User表已经有了,而且对应mysql数据库里面,已经建好了用户表。
我琢磨着不是要做登录功能嘛,那就得先往User表里头添加一条数据啊。用mysql front直接添加肯定是可以的,不过前段时间正好看了兔子发在B站的SSM商城系统,里面好像有个地方能够直接用Junit Test测试的,虽然这个系统不是SSM,不过应该也可以吧。
对了,pom.xml里面不是有这么一段配置嘛:
<!-- springboot test --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency>
这玩意怎么看都像是测试用的依赖啊,这是不是意味着,我就不用跟视频里面那样,去引入jar包了??
嗯,肯定是的。
##2. 做单元测试插入数据
OK,说干就干,创建一个测试包和测试类:
package com.edu.test; import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.context.web.WebAppConfiguration; @RunWith(SpringRunner.class) @SpringBootTest @WebAppConfiguration public class UserTest { }
打上注解,额,对了,我TM好像还没写dao方法呢,赶紧去写个。
创建一个dao包,这个包里面都放持久层的类,现在添加一个UserDao的接口。兔子关于SpringBoot的文章里面已经写过怎么使用JPA了,这边依葫芦画瓢。
直接写一个UserDao接口,继承一下JPA,注意,包别导错了。
package com.edu.dao; import org.springframework.data.jpa.repository.JpaRepository; import com.edu.entity.User; public interface UserDao extends JpaRepository<User, String>{ }
这样就ok了,然后,回到测试类,把这个接口注入进去。
add测试方法
@Test public void addUser(){ User user = new User(); user.setUserName("root"); user.setPassword("root"); user.setCreateTime("20210103"); user.setNickName("剽悍一小兔"); user.setRoleId("1");//默认1是管理员 user.setIsDelete("0");//默认不删除 user.setIsLogined("0");//默认没有登录 userDao.save(user); System.out.println("保存成功!"); }
开始测试:
哇,真的好了嘛,赶紧看下数据库??
OK了,真的来了。
##3. 单元测试优化
我叶小凡竟然也可以举一反三啦,兔子还没出这个SpringBoot版本的测试教程呢,我就凭借自己惊人的天赋,提前搞定了,哈哈哈。
兔子:“你这个单元测试还可以优化哦,亲~”
“啥情况,这不是很完美嘛?”
兔子:“这只是第一个单元测试,后面可能还会有很多其他的单元测试,你可以做一个通用的父类,这样就不用在每个测试类上打那么多注解了。”
于是,在兔子的指导下,我虽然不服,但还是照做了。
这样,在测试包下面,我们创建一个通用的测试父类。
package com.edu.test; import org.junit.After; import org.junit.Before; import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.context.web.WebAppConfiguration; @RunWith(SpringRunner.class) @SpringBootTest @WebAppConfiguration public class BaseTest { @Before public void init() { System.out.println("开始测试-----------------"); } @After public void after() { System.out.println("测试结束-----------------"); } }
然后,UserTest就继承这个父类,不用再加测试的注解了。
public class UserTest extends BaseTest{ }
验证一下,我们再写个测试方法,把刚才的数据删掉。
使用jpa进行update操作主要有两种方式:
1、调用保存实体的方法
1)保存一个实体:repository.save(T entity)
2)保存多个实体:repository.save(Iterable entities)
3)保存并立即刷新一个实体:repository.saveAndFlush(T entity)
注:若是更改,entity中必须设置了主键字段,不然不能对应上数据库中的记录,变成新增(数据库自动生成主键)或报错(数据库不自动生成主键)了
2、@Query注解,自己写JPQL语句
@Modifying @Query("update ShopCoupon sc set sc.deleted = true where sc.id in :ids") public void deleteByIds(@Param(value = "ids") List<String> ids);
1)update或delete时必须使用@Modifying对方法进行注解,才能使得ORM知道现在要执行的是写操作
2)有时候不加@Param注解参数,可能会报如下异常:
org.springframework.dao.InvalidDataAccessApiUsageException: Name must not be null or empty!; nested exception i is Java.lang.IllegalArgumentException: Name must not be null or empty!
以上资料摘自百度,哈哈,我该用哪一种呢?第二种方法比较亲切,直接用sql语句了,那就使用第二种吧。
按照百度到的说法,先在dao增加一个方法,自己写jpql语句,其实我也不太懂啥叫jpql语句,估计意思就是正常写sql,但是呢,字段的名字和User类里面的字段保持一致就行了。因为我发现,生成的表,还是用了下划线,是这样的:
于是,我就不能用下划线。
public interface UserDao extends JpaRepository<User, String>{ @Modifying @Query("update User u set u.isDelete = 1 where u.userName = :userName") public void deleteByUsername(@Param(value = "userName") String userName); }
新的测试方法,我要通过userName去做删除,删除不是真的删除,而是逻辑删除。
@Test public void deleteUser1(){ userDao.deleteByUsername("root"); System.out.println("删除成功"); }
运行,就报错了:
org.springframework.dao.InvalidDataAccessApiUsageException: Executing an update/delete query; nested exception is javax.persistence.TransactionRequiredException: Executing an update/delete query at … …
我靠,啥情况,我百度到的啊,怎么会错呢。
算了算了,这个不行,就换另一种方法。
兔子:“小伙子,你这样可不行啊,你好歹看下报啥错啊。。。”
“额,好吧,我看下哈!咦,这个好熟悉,TransactionRequiredException,Transaction这个单词的意思好像是那个事物吧。Required是需要的意思,莫非报错的意思是,让我加一个事物,是这样嘛?”
兔子:“别问我啊,你自己试一下不就知道了嘛!”
“好吧,我就加一个事物的注解看看。奇怪了,我明明百度的文章,哎。”
兔子:“事物一般是加在service方法里面的,你别加在dao里面啊。你想直接测试dao层的方法,这个想法没有错,不过你最好还是弄个service。”
“你的意思是,我再加一个service方法,加上事物,然后调用dao的方法?”
兔子:“嗯,或者你直接把事物加在test方法,也行的。”
说罢,兔哥帮我加上了注解,然后测试,竟然通过了。
这么说,我找的那篇文章,其实也是对的,等下奥,我翻下链接。”
兔子:“嗯,我看看。”
“就是这个…”