jquery循环 request中的list_TDD在Spring Boot项目中的应用

9d54425a-3a2f-eb11-8da9-e4434bdf6706.png

TDD

测试驱动开发的基本思想就是在开发功能代码之前,先编写测试代码。也就是说在明确要开发某个功能后,首先思考如何对这个功能进行测试,并完成测试代码的编写,然后编写相关的代码满足这些测试用例。然后循环进行添加其他功能,直到完全部功能的开发。

测试驱动开发的基本过程如下:

1) 明确当前要完成的功能。可以记录成一个 TODO 列表。

2) 快速完成针对此功能的测试用例编写。

3) 测试代码编译或执行不通过。

4) 编写对应的功能代码。

5) 测试通过。

6) 对代码进行重构,并保证测试通过。

7) 循环完成所有功能的开发。

TODO

假设在实际开发中有一个用户模块,该模块包括了用户的添加、查询、列表展示等功能。针对待开发的功能先做一个todo列表。

1)点击添加按钮,根据输入的信息添加一个用户信息,用户名存在提示异常,否则添加成功;

2)根据用户名,查询用户信息,返回用户名,用户昵称,用户职业,年龄与性别;

3)管理员权限的用户可以查看所有的用户信息;

Modules

为了实现上述功能点,首先选择开发框架。本次演示用基础开发框架为Spring Boot。项目管理使用的为maven。项目中用到模块之间的依赖关系为tdd-web->tdd-service->tdd-repo->tdd-domain->tdd-api。

9f54425a-3a2f-eb11-8da9-e4434bdf6706.png

TDD-Test Case

在设计测试用例时,用到的测试框架为spring-boot-starter-test。根据之前的todo列表。笔者设计了三个测试用例。分别用来测试UserController的add、query、list三个方法。写到这里,已经完成了tdd里面的第二步,根据需求设计测试用例。用例设计完成后,我们先执行,看看效果。三个用例都执行失败因为此时笔者还没有实现任何逻辑代码。

package com.mc.tdd.web.web.user;

import com.mc.tdd.web.TddApplication;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;

import java.awt.*;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

/**
 * @author M.C
 * @description UserControllerTest
 * @date 2019-03-10 10:45
 **/
@RunWith(SpringRunner.class)
@SpringBootTest(classes = TddApplication.class)
@AutoConfigureMockMvc
public class UserControllerTest {

    @Autowired
    MockMvc mockMvc;

    @Test
    public void testUserAdd() throws Exception {
        MvcResult mvcResult =mockMvc.perform(post("/user/add")
                .param("userName","tdd")
                .param("userNickname","mc")
                .param("gender","male")
                .param("age","25")
                .param("occupation","spring boot developer")
        ).andExpect(status().isCreated()).andReturn();
    }

    @Test
    public void testUserQuery() throws Exception {
        mockMvc.perform(get("/user/get/{userName}","tdd")
                .accept(MediaType.APPLICATION_JSON))
                .andDo(print())
                .andExpect(status().isOk())
                .andExpect(MockMvcResultMatchers.jsonPath("$.userName").isNotEmpty());
    }

    @Test
    public void testUserList() throws Exception {
        mockMvc.perform(get("/user/list")
                .accept(MediaType.APPLICATION_JSON))
                .andDo(print())
                .andExpect(status().isOk())
                .andExpect(MockMvcResultMatchers.jsonPath("$.users").exists())
                .andExpect(MockMvcResultMatchers.jsonPath("$.users[*].userName").isNotEmpty());
    }

}

a054425a-3a2f-eb11-8da9-e4434bdf6706.png

TDD-Web

此时我们简单的浏览一下tdd-web模块里面的内容。TddApplication 为Spring Boot的入口类。UserControllerTest为之UserController的测试类。接下来,笔者将分别实现用户的添加,查询和列表显示功能在web模块中的代码以及依赖接口的空实现。

a154425a-3a2f-eb11-8da9-e4434bdf6706.png

UserDto类,主要用来接收web端传入的参数。

package com.mc.tdd.domain.user;

/**
 * @author M.C
 * @description UserDto
 * @date 2019-03-10 10:40
 **/
public class UserDto {
    private String userName;
    private String userNickName;
    private Integer age;
    private String gender;
    private String occupation;

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getUserNickName() {
        return userNickName;
    }

    public void setUserNickName(String userNickName) {
        this.userNickName = userNickName;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public String getOccupation() {
        return occupation;
    }

    public void setOccupation(String occupation) {
        this.occupation = occupation;
    }
}

Response类,用于给web端进行交互使用。

package com.mc.tdd.domain.response;

import java.io.Serializable;

/**
 * @author M.C
 * @description Response
 * @date 2019-03-10 12:43
 **/
public class Response implements Serializable {
    private int code ;
    private String message;
    private Object data;

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }
}

UserService接口,定义相关的操作。

package com.mc.tdd.api.user;

import com.mc.tdd.domain.user.UserDto;

import java.util.List;
import java.util.Optional;

/**
 * @author M.C
 * @description UserService
 * @date 2019-03-10 9:02
 **/
public interface UserService {
    public Optional<UserDto> add(UserDto userDto);
    public Optional<UserDto> query(String userName);
    public Optional<List<UserDto>> list();
}

UserServiceImpl的接口实现类。目前都是接口的空实现。

package com.mc.tdd.service.user.impl;

import com.mc.tdd.api.user.UserService;
import com.mc.tdd.domain.user.UserDto;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Optional;

/**
 * @author M.C
 * @description UserServiceImpl
 * @date 2019-03-10 9:14
 **/
@Service
public class UserServiceImpl implements UserService {
    @Override
    public Optional<UserDto> add(UserDto userDto) {
        return null;
    }

    @Override
    public Optional<UserDto> query(String userName) {
        return null;
    }

    @Override
    public Optional<List<UserDto>> list() {
        return null;
    }
}

UserController的实现代码

package com.mc.tdd.web.controller;

import com.mc.tdd.api.user.UserService;
import com.mc.tdd.domain.response.Response;
import com.mc.tdd.domain.user.UserDto;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.List;
import java.util.Optional;

/**
 * @author M.C
 * @description UserController
 * @date 2019-03-10 12:14
 **/
@Controller
@RequestMapping("/user")
public class UserController {

    @Resource
    UserService userService;

    @PostMapping("/add")
    @ResponseBody
    public Response add(UserDto userDto){
        Response response = new Response();
        Optional<UserDto> result = userService.add(userDto);
        response.setData(result.get());
        return response;
    }

    @GetMapping("/get")
    @ResponseBody
    public Response query(@PathVariable("userName") String userName){
        Response response = new Response();
        Optional<UserDto> result = userService.query(userName);
        response.setData(result.get());
        return response;
    }

    @GetMapping("/list")
    @ResponseBody
    public Response list(){
        Response response = new Response();
        Optional<List<UserDto>> result =userService.list();
        response.setData(result.get());
        return response;
    }
}

当controller代码设计完毕后,再次执行之前的测试用例。结果还是失败。因为UserController依赖service模块的UserService接口。所以如果测试该controller的话,需要将UserService接口进行mock处理。

a254425a-3a2f-eb11-8da9-e4434bdf6706.png

Mock Service

由于UserController需要使用UserService,不过此时UserService目前还未实现。因此在进行UserController测试时,需要将UserService做mock,使用到的注解为@MockBean。

改造后的UserControllerTest类实现如下

package com.mc.tdd.web.web.user;

import com.mc.tdd.api.user.UserService;
import com.mc.tdd.domain.user.UserDto;
import com.mc.tdd.web.TddApplication;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;

import java.util.List;
import java.util.ArrayList;
import java.util.Optional;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

/**
 * @author M.C
 * @description UserControllerTest
 * @date 2019-03-10 10:45
 **/
@RunWith(SpringRunner.class)
@SpringBootTest(classes = TddApplication.class)
@AutoConfigureMockMvc
public class UserControllerTest {

    @Autowired
    MockMvc mockMvc;

    @MockBean
    UserService userService;

    @Test
    public void testUserAdd() throws Exception {
        UserDto userDto = new UserDto();
        userDto.setUserName("tdd");
        userDto.setUserNickName("mc");
        userDto.setGender("male");
        userDto.setAge(29);
        userDto.setOccupation("spring boot developer");
        Optional<UserDto> mockUserDto = Optional.of(userDto);

        Mockito.when(userService.add(Mockito.any(UserDto.class))).thenReturn(mockUserDto);

        MvcResult mvcResult = mockMvc.perform(post("/user/add")
                .param("userName","tdd")
                .param("userNickname","mc")
                .param("gender","male")
                .param("age","25")
                .param("occupation","spring boot developer"))
                .andExpect(status().isOk())
                .andExpect(MockMvcResultMatchers.jsonPath("$.code").value("0"))
                .andExpect(MockMvcResultMatchers.jsonPath("$.data.userName").value("tdd"))
                .andReturn();
    }

    @Test
    public void testUserQuery() throws Exception {
        UserDto userDto = new UserDto();
        userDto.setUserName("tdd");
        userDto.setUserNickName("mc");
        userDto.setGender("male");
        userDto.setAge(29);
        userDto.setOccupation("spring boot developer");
        Optional<UserDto> mockUserDto = Optional.of(userDto);

        Mockito.when(userService.query(Mockito.anyString())).thenReturn(mockUserDto);

        MvcResult mvcResult = mockMvc.perform(get("/user/query/{userName}","tdd"))
                .andExpect(status().isOk())
                .andExpect(MockMvcResultMatchers.jsonPath("$.code").value("0"))
                .andExpect(MockMvcResultMatchers.jsonPath("$.data.userName").value("tdd"))
                .andReturn();
    }

    @Test
    public void testUserList() throws Exception {
        UserDto userDto = new UserDto();
        userDto.setUserName("tdd");
        userDto.setUserNickName("mc");
        userDto.setGender("male");
        userDto.setAge(29);
        userDto.setOccupation("spring boot developer");

        List<UserDto> userDtoList = new ArrayList<>();
        userDtoList.add(userDto);

        Optional<List<UserDto>> mockUserDtoList = Optional.of(userDtoList);

        Mockito.when(userService.list()).thenReturn(mockUserDtoList);

        MvcResult mvcResult = mockMvc.perform(get("/user/list")
                .accept(MediaType.APPLICATION_JSON))
                .andDo(print())
                .andExpect(status().isOk())
                .andExpect(MockMvcResultMatchers.jsonPath("$.code").value("0"))
                .andExpect(MockMvcResultMatchers.jsonPath("$.data[0].userName").value("tdd"))
                .andReturn();
    }

}

执行该测试类,检查实现的功能是否符合预期。其中两个用例执行成功,一个失败。失败的原因为404及请求的url未找到。这时候我们具体排查一下失败的原因:请求的url为get("/user/query/{userName}。但是UserController里面定义方法的@GetMapping("/query")。所以这次失败的原因为代码实现的bug。修改代码为@GetMapping("/query/{userName}")。解决该bug后重新执行测试用例。

a454425a-3a2f-eb11-8da9-e4434bdf6706.png

a654425a-3a2f-eb11-8da9-e4434bdf6706.png

到此,我们的UserController中的功能就算基本开发完成了。看到这里是不是觉得TDD根本没有想象中的那么难呢?

Mock-JPA

接下来我们开发UserService中定义的接口。因为我们采用的是TDD的思想。所以第一步还是创建测试用例。由于该接口依赖于UserRepo,所以在该测试类中添加mock。将未做实现的UserRepo做mock处理。

在做mock之前,先浏览一下UserRepo中的接口定义。

package com.mc.tdd.repo.user;

import com.mc.tdd.domain.user.User;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.List;

/**
 * @author M.C
 * @description UserRepo
 * @date 2019-03-10 15:36
 **/
public interface UserRepo extends JpaRepository<User,Long> {
    public User saveDto(User user);
    public User queryDto(String userName);
    public List<User> listDto();
}

结合UserRepo的接口定义与UserService的功能,最终设计的测试用例如下。

package com.mc.tdd.api.user;

import com.mc.tdd.domain.user.User;
import com.mc.tdd.domain.user.UserDto;
import com.mc.tdd.repo.user.UserRepo;
import com.mc.tdd.web.TddApplication;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.context.junit4.SpringRunner;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

/**
 * @author M.C
 * @description UserServiceTest
 * @date 2019-03-10 15:19
 **/
@RunWith(SpringRunner.class)
@SpringBootTest(classes = TddApplication.class)
public class UserServiceTest {

    @Resource
    UserService userService;

    @MockBean
    UserRepo userRepo;

    @Test
    public void testUserAdd(){
        User user = new User();
        user.setUserName("tdd");
        user.setUserNickName("mc");
        user.setGender("male");
        user.setAge(29);
        user.setOccupation("spring boot developer");
        Mockito.when(userRepo.saveDto(Mockito.any(User.class))).thenReturn(user);

        UserDto userDto = new UserDto();
        userDto.setUserName("tdd");
        userDto.setUserNickName("mc");
        userDto.setGender("male");
        userDto.setAge(29);
        userDto.setOccupation("spring boot developer");

        Optional<UserDto> result = userService.add(userDto);

        Assert.assertEquals(userDto.getUserName(),result.get().getUserName());
    }

    @Test
    public void testUserQuery(){
        User user = new User();
        user.setUserName("tdd");
        user.setUserNickName("mc");
        user.setGender("male");
        user.setAge(29);
        user.setOccupation("spring boot developer");

        Mockito.when(userRepo.queryDto(Mockito.anyString())).thenReturn(user);

        Optional<UserDto> result = userService.query("tdd");
        Assert.assertEquals("tdd",result.get().getUserName());
    }

    @Test
    public void testUserList(){
        User user = new User();
        user.setUserName("tdd");
        user.setUserNickName("mc");
        user.setGender("male");
        user.setAge(29);
        user.setOccupation("spring boot developer");
        
        List<User> userList = new ArrayList<>();
        userList.add(user);
        
        Mockito.when(userRepo.listDto()).thenReturn(userList);
        
        Optional<List<UserDto>> result = userService.list();
        Assert.assertEquals(Boolean.TRUE.booleanValue(),result.get().size()>0);
    }

}

执行完毕测试用例后,笔者发现其中一个测试用例执行失败。userService.query("tdd"); 期望结果中的userName为tdd,但是接口实际返回的却是mc。其中mc这个值为userNickName。排查代码发现是因为给userName赋值时错误的将userNickName赋给了userName。userDtoTemp.setUserName(result.getUserNickName()); 解决完该bug后,重新执行测试用例。

aa54425a-3a2f-eb11-8da9-e4434bdf6706.png

ab54425a-3a2f-eb11-8da9-e4434bdf6706.png

为了方便代码的阅读,此处将UserServiceImpl最终的实现代码粘贴出来。

package com.mc.tdd.service.user.impl;

import com.mc.tdd.api.user.UserService;
import com.mc.tdd.domain.user.User;
import com.mc.tdd.domain.user.UserDto;
import com.mc.tdd.repo.user.UserRepo;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

/**
 * @author M.C
 * @description UserServiceImpl
 * @date 2019-03-10 9:14
 **/
@Service
public class UserServiceImpl implements UserService {

    @Resource
    UserRepo userRepo;

    @Override
    public Optional<UserDto> add(UserDto userDto) {
        User user = new User();
        user.setUserName(userDto.getUserName());
        user.setUserNickName(userDto.getUserNickName());
        user.setAge(userDto.getAge());
        user.setGender(userDto.getGender());
        user.setOccupation(userDto.getOccupation());
        User result = userRepo.saveDto(user);

        UserDto userDtoTemp = new UserDto();
        userDtoTemp.setUserName(result.getUserName());
        userDtoTemp.setUserNickName(result.getUserNickName());
        userDtoTemp.setAge(result.getAge());
        userDtoTemp.setGender(result.getGender());
        userDtoTemp.setOccupation(result.getOccupation());

        return Optional.of(userDtoTemp);
    }

    @Override
    public Optional<UserDto> query(String userName) {
        User result = userRepo.queryDto(userName);

        UserDto userDtoTemp = new UserDto();
        userDtoTemp.setUserName(result.getUserName());
        userDtoTemp.setUserNickName(result.getUserNickName());
        userDtoTemp.setAge(result.getAge());
        userDtoTemp.setGender(result.getGender());
        userDtoTemp.setOccupation(result.getOccupation());

        return Optional.of(userDtoTemp);
    }

    @Override
    public Optional<List<UserDto>> list() {
        List<User> userList = userRepo.listDto();
        List<UserDto> userDtoList = new ArrayList<>();
        userList.forEach( result -> {
            UserDto userDtoTemp = new UserDto();
            userDtoTemp.setUserName(result.getUserName());
            userDtoTemp.setUserNickName(result.getUserNickName());
            userDtoTemp.setAge(result.getAge());
            userDtoTemp.setGender(result.getGender());
            userDtoTemp.setOccupation(result.getOccupation());
            userDtoList.add(userDtoTemp);
        });
        return Optional.of(userDtoList);
    }
}

JPA-Test

目前就剩下UserRepo的类未实现。所以本章节重点介绍JPA相关的实现与测试。根据之前的思路。笔者还是先设计测试用例。

package com.mc.tdd.repo.user;

import com.mc.tdd.domain.user.User;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager;
import org.springframework.test.context.junit4.SpringRunner;

import javax.annotation.Resource;
import java.util.List;

/**
 * @author M.C
 * @description UserRepoTest
 * @date 2019-03-11 16:31
 **/
@RunWith(SpringRunner.class)
@DataJpaTest
public class UserRepoTest {

    @Autowired
    private TestEntityManager entityManager;

    @Resource
    UserRepo userRepo;

    @Test
    public void testUserAdd(){
        User user = new User();
        user.setUserName("tdd");
        user.setUserNickName("mc");
        user.setGender("male");
        user.setAge(29);
        user.setOccupation("spring boot developer");
        User result = userRepo.saveDto(user.getUserName(),user.getUserNickName(),user.getAge(),user.getGender(),user.getOccupation());
        Assert.assertEquals("tdd",result.getUserName());
    }

    @Test
    public void testUserQuery(){
        User user = new User();
        user.setUserName("tdd");
        user.setUserNickName("mc");
        user.setGender("male");
        user.setAge(29);
        user.setOccupation("spring boot developer");
        entityManager.persist(user);
        User result = userRepo.queryDto("tdd");
        Assert.assertEquals("tdd",result.getUserName());
    }

    @Test
    public void testUserList(){
        User user = new User();
        user.setUserName("tdd");
        user.setUserNickName("mc");
        user.setGender("male");
        user.setAge(29);
        user.setOccupation("spring boot developer");
        entityManager.persist(user);

        List<User> result = userRepo.listDto();
        Assert.assertEquals(Boolean.TRUE.booleanValue(),result.size()>0);
    }
}

执行之后查看失败原因。因为目前位置演示用的JPA类中还没有做任何的实现。同时在接口定义时,没有使用JPA默认的方法命名规则。所以jpa会认为我们设计的接口是错误的。根据错误提示。实现具体的jpa功能。

ac54425a-3a2f-eb11-8da9-e4434bdf6706.png

实现后的jpa类

package com.mc.tdd.repo.user;

import com.mc.tdd.domain.user.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

import java.util.List;

/**
 * @author M.C
 * @description UserRepo
 * @date 2019-03-10 15:36
 **/
public interface UserRepo extends JpaRepository<User,Long> {

    @Query(value = "insert into tdd_user(user_name,user_nick_name,user_age,user_gender,user_occupation) value (:userName,:userNickName,:age,:gender,:occupation)",nativeQuery = true)
    public User saveDto(@Param("userName") String userName,@Param("userNickName") String userNickName,@Param("age") Integer age,@Param("gender") String gender,@Param("occupation") String occupation);

    @Query(value = "select * from tdd_user as tddUser where tddUser.user_name = :userName",nativeQuery = true)
    public User queryDto(@Param("userName") String userName);

    @Query(value = "select * from tdd_user",nativeQuery = true)
    public List<User> listDto();
}

再次执行之前的测试用例,发现有一个用例执行失败,失败原因为sql异常。排查失败原因,是因为笔者将 sql的 values错误的写成了value。少些了一个s。再次执行查看结果发现还是有异常Method is only allowed for a query。只要有异常就继续排查。失败原因是为insert或update操作需要显示声明为@Modify。

ad54425a-3a2f-eb11-8da9-e4434bdf6706.png

ae54425a-3a2f-eb11-8da9-e4434bdf6706.png

b054425a-3a2f-eb11-8da9-e4434bdf6706.png

调试到这里,读者是不是在想总算可以松口气了。因为所有的单元测试用例都已经pass了。笔者认为,目前只是完成了一些基本的单元测试。接下来要做的是集成测试。把之前实现的模块集成到一起进行测试。

Integration Testing

TDD不仅适用于单元测试阶段,集成测试阶段也同样适用。这时候的测试用例可以充分参考之前的设计场景来进行测试。在测试用例设计过程中,需要注意的是,接口之间的调用就要用实际的接口而不能使用mock接口了。

我们的集成测试用例设计如下。

package com.mc.tdd.web.web.user;

import com.mc.tdd.web.TddApplication;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

/**
 * @author M.C
 * @description UserControllerTest
 * @date 2019-03-10 10:45
 **/
@RunWith(SpringRunner.class)
@SpringBootTest(classes = TddApplication.class)
@AutoConfigureMockMvc
public class UserControllerIntegrationTest {

    @Autowired
    MockMvc mockMvc;

    @Test
    public void testUserAdd() throws Exception {
        MvcResult mvcResult = mockMvc.perform(post("/user/add")
                .param("userName","tdd")
                .param("userNickname","mc")
                .param("gender","male")
                .param("age","25")
                .param("occupation","spring boot developer"))
                .andExpect(status().isOk())
                .andExpect(MockMvcResultMatchers.jsonPath("$.code").value("0"))
                .andExpect(MockMvcResultMatchers.jsonPath("$.data").value("1"))
                .andReturn();
    }

    @Test
    public void testUserQuery() throws Exception {
        MvcResult mvcResult = mockMvc.perform(get("/user/query/{userName}","tdd"))
                .andExpect(status().isOk())
                .andExpect(MockMvcResultMatchers.jsonPath("$.code").value("0"))
                .andExpect(MockMvcResultMatchers.jsonPath("$.data.userName").value("tdd"))
                .andReturn();
    }

    @Test
    public void testUserList() throws Exception {
        MvcResult mvcResult = mockMvc.perform(get("/user/list")
                .accept(MediaType.APPLICATION_JSON))
                .andDo(print())
                .andExpect(status().isOk())
                .andExpect(MockMvcResultMatchers.jsonPath("$.code").value("0"))
                .andExpect(MockMvcResultMatchers.jsonPath("$.data[0].userName").value("tdd"))
                .andReturn();
    }

}

b154425a-3a2f-eb11-8da9-e4434bdf6706.png

b254425a-3a2f-eb11-8da9-e4434bdf6706.png

针对执行过程中遇到的异常逐个分析排查。UserRepo注入异常,是因为spring boot 在扫描时,没有将UserRepo进行初始化并交给Spring容器来托管。问题修复方法添加 @EnableJpaRepositories(basePackages={"com.mc.tdd.repo"})。

b354425a-3a2f-eb11-8da9-e4434bdf6706.png

Executing an update/delete query; nested exception is javax.persistence.TransactionRequiredException: Executing an update/delete query。失败原因是update或delete或insert相关的操作需要添加事物声明。

b454425a-3a2f-eb11-8da9-e4434bdf6706.png

b554425a-3a2f-eb11-8da9-e4434bdf6706.png

TDD

关于测试驱动开发的相关理论知识,感觉这篇文章写的还是不错的。浅谈测试驱动开发(TDD)。如果读者感兴趣可以查看该文章进一步了解。本文的侧重点是从实战的角度来进一步的体会什么是TDD。以及在实际项目中如何运用TDD。如有不足之处还请各位读者指正。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值