Spring Boot:对DAO、Service和Controller进行单元测试
程序员文章站
2022-04-26 10:31:54
...
Spring mvc尽可能把逻辑封装在Model层,Controller只负责UI展示的处理,这样Model层就更加容易复用,在各个模块进行调用。同时也方便单元测试,文章代码Kotlin语言编写。
DAO & Service层单元测试
dao和Service的测试比较简单,就是通过Spring mvc框架的自动注入获取到实例,即可对接口实现测试。
@Repository
interface UserRepository {
@Select("SELECT * FROM User WHERE ID = #{id}")
fun findById(@Param("id") integer: Int?): User
@Select("SELECT * FROM User")
fun findAll(): List<User>
@Insert("INSERT INTO User(id,name) VALUES(#{id}, #{name})")
@Options(useGeneratedKeys = true, keyProperty = "id")
fun insert(user: User)
}
测试UserRepository
,只需要使用@RunWith
和@SpringBootTest
就能确定单元测试的环境,实现自动注入。
@RunWith(SpringRunner::class)
@SpringBootTest
class UserRepositoryTest {
@Autowired
lateinit var repository: UserRepository
@Test
@Throws(Exception::class)
fun findById() {
val user = repository.findById(1)
assertNotNull(user)
assertEquals(1, user.id)
println("id:" + user.id + ",name:" + user.name)
}
@Test
@Throws(Exception::class)
fun findAll() {
val users = repository.findAll()
users.forEach { println(it.id) }
}
@Test
@Throws(Exception::class)
fun insert() {
val user = User(1, "Wiki")
repository.insert(user)
}
}
Controller单元测试
Controller层是我们面向用户的层,负责把Model层的数据按照一定的格式返回给用户,通常而言都是json
和网页
。
方案一:Java接口测试,和dao层测试类同(推荐)
我们知道可以通过request.setAttribute
对页面进行传参数
// 不推荐
@Controller
class UserController {
@RequestMapping("/user")
fun show(request: HttpServletRequest, id:Int): String {
val user = User(id, "Wiki")
request.setAttribute("name", "Wiki")
return "/user.jsp"
}
}
但是这种方式并不方便测试,建议使用以下方式对页面进行传参数,建议采用一下方案进行编写代码,一方面逻辑清晰,另一方面方便进行单元测试。
// 推荐
@Controller
class UserController {
@RequestMapping("/user")
fun show(map: MutableMap<String, Any>, id: Int): String {
val user = User(id, "Wiki")
map["user"] = user
return "/user.jsp"
}
}
那么对UserController进行单元测试就变得非常的简单,不涉及到JSON、网页
@RunWith(SpringRunner::class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class UserControllerTest {
@Autowired
lateinit var controller: UserController
@Test
@Throws(Exception::class)
fun show() {
val map = HashMap<String, Any>()
controller.show(map, 1)
val user = map["user"] as User
assertNotNull(user)
assertEquals(1, user.id)
println("id:" + user.id + ",name:" + user.name)
}
}
下面举例测试返回json的@RestController
@RestController
class UserApiController {
@RequestMapping("/api/getUser")
fun getUser(id: Int): User {
val user = User(id, "Wiki")
return user
}
}
测试代码:
@RunWith(SpringRunner::class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class UserApiControllerTest {
@Autowired
lateinit var controller: UserApiController
@Test
@Throws(Exception::class)
fun getUser() {
val user = controller.getUser(1)
assertNotNull(user)
assertEquals(1, user.id)
println("id:" + user.id + ",name:" + user.name)
}
}
方案二:MockMvc
上述的方案一其实和Service测试都是类似的,但是有时候我们还是需要测试真实反馈的内容,包括网页,JSON信息,使用MockMvc也可以实现。
@RunWith(SpringRunner::class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureMockMvc
class UserApiControllerMockMvcTest {
@Autowired
lateinit var mvc: MockMvc
@Test
@Throws(Exception::class)
fun getUser() {
mvc.perform(MockMvcRequestBuilders.get("/api/getUser?id=1").accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk)
.andExpect(content().string(equalTo<String>("{\"id\":1,\"name\":\"Wiki\"}")))
}
}
方案三:TestRestTemplate
,但是有时候我们还是需要使用URL对方案进行测试,通过访问URL,对比返回的内容,属于真实的浏览器请求。
@RunWith(SpringRunner::class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class UserApiControllerTemplateTest {
@LocalServerPort
var port: Int = 0
lateinit var base: URL
@Autowired
lateinit var template: TestRestTemplate
@Before
@Throws(Exception::class)
fun setUp() {
this.base = URL("http://localhost:$port/")
}
@Test
@Throws(Exception::class)
fun getUser() {
val response = template.getForEntity(base.toString() + "api/getUser?id=1",String::class.java)
assertThat(response.body, equalTo<String>("{\"id\":1,\"name\":\"Wiki\"}"))
}
}
Demo代码
https://github.com/taoweiji/GradleKotlinSpringBootMybatisSQLiteDemo
推荐阅读
-
Spring Boot从Controller层进行单元测试的实现
-
jasypt 集成spring、spring boot 对配置文件中的配置和属性进行加密
-
controller 和dao_[易学springboot]对controller层进行单元测试
-
单元测试总结:Dao层、Service层和Controller层
-
Spring对Controller、Service、Dao进行Junit单元测试总结
-
Spring Boot:对DAO、Service和Controller进行单元测试
-
Spring框架进行Service和DAO单元测试
-
Spring对Controller、Service、Dao进行Junit单元测试总结
-
Spring对Controller、Service、Dao进行Junit单元测试总结
-
Spring对Controller、Service、Dao进行Junit单元测试总结