节操换外语 2018-04-05
【内容指引】
关闭微服务项目的缓存开关;
改造dto层代码;
改造dao层代码;
改造service.impl层的list方法;
调整单元测试类的testList方法代码。
在正式进行测试驱动开发之前,我们需要关闭项目的缓存配置。由于从“云开发”平台生成的微服务初始化代码默认启用了Redis缓存(建议以Docker的方式安装及启动Redis),为避免因为缓存导致测试数据不准确,可以关闭缓存的开关。
如下图所示,在"DocApplicationTests"中将“//TODO”提示这行删除掉即可:

在“DocApplication”中将“@EnableCaching”这个注解注释掉,就关掉了缓存开关:

在查询文档分类(Category)列表时,查询的参数通过“DTO数据传输对象”CategoryDTO传递。默认情况下,“云开发”平台初始化的DTO类代码中的字段来自于领域类中数据类型为String的字段,除此外,增加一个keyword字段。
keyword字段用于标准查询,其它字段用于高级查询。这里介绍下标准查询和高级查询的区别。
提示
由于本例中Category领域类仅包含name(分类名称)这一个String类型的字段,不便于区分标准查询和高级查询。我们假设Category类中还含有一个memo(分类说明)字段,那么标准查询和高级查询的用途如下:
标准查询
标准查询,就是“或”关系的匹配。客户端仅提供一个“查询关键字”,然后从Category领域类对应的数据表"tbl_category"的多个String字段中匹配该关键字(忽略大小写),只要任何一个字段匹配成功,即成为查询结果之一。比如,关键字为“AA”,那么如果分类名称(name)中含有“AA”,或者分类说明(memo)中含有“AA”,都是符合条件的。
高级查询
高级查询,就是“且”关系的匹配。客户端提供多个关键字,然后从Category领域类对应的数据表"tbl_category"的多个String字段中分别匹配这些关键字,只有所有字段的赋值均匹配成功,才能成为查询结果之一。比如,分类名称关键字为“AA”,分类说明关键字为“BB”,那么只有分类名称(name)中含有“AA”,并且分类说明(memo)中含有“BB”的数据才是符合条件的。

keyword字段是约定用于标准查询的参数,不可删除!
根据实际查询需要,将不适合用于查询的字段删除掉,包含私有字段、构造函数、get和set属性。
本例中由于领域类Category中仅含一个String类型字段name,所以不必分标准查询和高级查询,所以将用于高级查询的字段“name”删除掉。
本例中,查询文档分类时需指定所属的项目,所以增加一个projectId字段,相应修改带参构造函数和Getter、Setter。Mac操作系统下使用IntelliJ IDEA编码时可以用“Command + N”快捷键:

修改后代码:
package top.cloudev.doc.dto; import java.io.Serializable; /** * Category(文档分类) 的DTO数据传输对象 * Created by Mac.Manon on 2018/04/02 */ public class CategoryDTO implements Serializable { private static final long serialVersionUID = 1L; /** * 关键字(标准查询) */ private String keyword; /** * 文档分类所属的项目 */ private Long projectId; /** *空构造函数 * */ public CategoryDTO(){ } public CategoryDTO(String keyword, Long projectId) { this.keyword = keyword; this.projectId = projectId; } /** *Getter,Setter * */ public String getKeyword() { return keyword; } public void setKeyword(String keyword) { this.keyword = keyword; } public Long getProjectId() { return projectId; } public void setProjectId(Long projectId) { this.projectId = projectId; } }
dao层采用JPA接口的方式实现数据查询,根据DTO中字段的调整,修改这里的接口(增加了projectId参数):
修改前代码:
package top.cloudev.doc.dao; import top.cloudev.doc.domain.Category; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; /** * 领域类 Category(文档分类) 的DAO Repository接口层 * Created by Mac.Manon on 2018/04/02 */ //@RepositoryRestResource(path = "newpath") public interface CategoryRepository extends JpaRepository<Category,Long> { Page<Category> findByIsDeletedFalse(Pageable pageable); // 标准查询 Page<Category> findByNameContainingAndIsDeletedFalseAllIgnoringCase(String name, Pageable pageable); }
修改后代码:

package top.cloudev.doc.dao; import top.cloudev.doc.domain.Category; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; /** * 领域类 Category(文档分类) 的DAO Repository接口层 * Created by Mac.Manon on 2018/04/02 */ //@RepositoryRestResource(path = "newpath") public interface CategoryRepository extends JpaRepository<Category,Long> { // 默认列表 Page<Category> findByProjectIdAndIsDeletedFalse(Long projectId, Pageable pageable); // 标准查询 Page<Category> findByNameContainingAllIgnoringCaseAndProjectIdAndIsDeletedFalse(String name, Long projectId, Pageable pageable); }
由于dao层的查询接口已修改,相应调整服务实现层UserServiceImpl中getPageData方法调用的方法名及参数。这里利用"dto.getProjectId()"给增加的参数传值:

打开文档分类的单元测试类代码,找到"testList()"方法,对其中调用Dao层数据访问接口的代码进行调整(正常情况下应该在“测试无搜索列表”、“测试标准查询”和“测试高级查询”三处有对dao接口的调用,本例中因没有高级查询,所以仅需修改两处):

调整后代码如下:


/** * 测试无搜索列表 */ /**---------------------测试用例赋值开始---------------------**/ //TODO 将下面的null值换为测试参数 Pageable pageable=new PageRequest(0,10, Sort.Direction.DESC,"categoryId"); // 期望获得的结果数量(默认有两个测试用例,所以值应为"2L",如果新增了更多测试用例,请相应设定这个值) expectResultCount = null; /**---------------------测试用例赋值结束---------------------**/ // 直接通过dao层接口方法获得期望的数据 Page<Category> pagedata = categoryRepository.findByProjectIdAndIsDeletedFalse(c1.getCategoryId(), pageable); expectData = JsonPath.read(Obj2Json(pagedata),"$").toString(); MvcResult mvcResult = mockMvc .perform( MockMvcRequestBuilders.get("/category/list") .accept(MediaType.APPLICATION_JSON) ) // 打印结果 .andDo(print()) // 检查状态码为200 .andExpect(status().isOk()) // 检查返回的数据节点 .andExpect(jsonPath("$.pagedata.totalElements").value(expectResultCount)) .andExpect(jsonPath("$.dto.keyword").isEmpty()) .andExpect(jsonPath("$.dto.name").isEmpty()) .andReturn(); // 提取返回结果中的列表数据及翻页信息 responseData = JsonPath.read(mvcResult.getResponse().getContentAsString(),"$.pagedata").toString(); System.out.println("=============无搜索列表期望结果:" + expectData); System.out.println("=============无搜索列表实际返回:" + responseData); Assert.assertEquals("错误,无搜索列表返回数据与期望结果有差异",expectData,responseData); /** * 测试标准查询 */ /**---------------------测试用例赋值开始---------------------**/ //TODO 将下面的null值换为测试参数 dto = new CategoryDTO(); dto.setKeyword(null); dto.setProjectId(c1.getProjectId()); pageable=new PageRequest(0,10, Sort.Direction.DESC,"categoryId"); // 期望获得的结果数量 expectResultCount = null; /**---------------------测试用例赋值结束---------------------**/ String keyword = dto.getKeyword().trim(); // 直接通过dao层接口方法获得期望的数据 pagedata = categoryRepository.findByNameContainingAllIgnoringCaseAndProjectIdAndIsDeletedFalse(keyword, dto.getProjectId(), pageable); expectData = JsonPath.read(Obj2Json(pagedata),"$").toString(); mvcResult = mockMvc .perform( MockMvcRequestBuilders.get("/category/list") .param("keyword",dto.getKeyword()) .accept(MediaType.APPLICATION_JSON) ) // 打印结果 .andDo(print()) // 检查状态码为200 .andExpect(status().isOk()) // 检查返回的数据节点 .andExpect(jsonPath("$.pagedata.totalElements").value(expectResultCount)) .andExpect(jsonPath("$.dto.keyword").value(dto.getKeyword())) .andExpect(jsonPath("$.dto.name").isEmpty()) .andReturn(); // 提取返回结果中的列表数据及翻页信息 responseData = JsonPath.read(mvcResult.getResponse().getContentAsString(),"$.pagedata").toString(); System.out.println("=============标准查询期望结果:" + expectData); System.out.println("=============标准查询实际返回:" + responseData); Assert.assertEquals("错误,标准查询返回数据与期望结果有差异",expectData,responseData);