测试驱动开发实践2————测试驱动开发之前

【内容指引】
关闭微服务项目的缓存开关;
改造dto层代码;
改造dao层代码;
改造service.impl层的list方法;
调整单元测试类的testList方法代码。

一、关闭项目的缓存开关

在正式进行测试驱动开发之前,我们需要关闭项目的缓存配置。由于从“云开发”平台生成的微服务初始化代码默认启用了Redis缓存(建议以Docker的方式安装及启动Redis),为避免因为缓存导致测试数据不准确,可以关闭缓存的开关。

如下图所示,在"DocApplicationTests"中将“//TODO”提示这行删除掉即可:

测试驱动开发实践2————测试驱动开发之前

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

测试驱动开发实践2————测试驱动开发之前

二、改造dto层代码

在查询文档分类(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”的数据才是符合条件的。

测试驱动开发实践2————测试驱动开发之前

1.keyword字段不可删除

keyword字段是约定用于标准查询的参数,不可删除!

2.CategoryDTO其它字段

根据实际查询需要,将不适合用于查询的字段删除掉,包含私有字段、构造函数、get和set属性。
本例中由于领域类Category中仅含一个String类型字段name,所以不必分标准查询和高级查询,所以将用于高级查询的字段“name”删除掉。

3.为CategoryDTO增加字段

本例中,查询文档分类时需指定所属的项目,所以增加一个projectId字段,相应修改带参构造函数和Getter、Setter。Mac操作系统下使用IntelliJ IDEA编码时可以用“Command + N”快捷键:

测试驱动开发实践2————测试驱动开发之前

修改后代码:

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层代码

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

}

修改后代码:

测试驱动开发实践2————测试驱动开发之前

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

}

四、改造service.impl层的getPageData方法

由于dao层的查询接口已修改,相应调整服务实现层UserServiceImpl中getPageData方法调用的方法名及参数。这里利用"dto.getProjectId()"给增加的参数传值:

测试驱动开发实践2————测试驱动开发之前

五、调整单元测试类的testList方法代码

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

测试驱动开发实践2————测试驱动开发之前

调整后代码如下:

测试驱动开发实践2————测试驱动开发之前

测试驱动开发实践2————测试驱动开发之前

/**
         * 测试无搜索列表
         */

        /**---------------------测试用例赋值开始---------------------**/
        //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);

相关推荐