美文网首页Spring-Boot我爱编程
Spring Boot:对DAO、Service和Control

Spring Boot:对DAO、Service和Control

作者: ImWiki | 来源:发表于2018-05-25 13:18 被阅读121次

    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:对DAO、Service和Control

      本文链接:https://www.haomeiwen.com/subject/qclyjftx.html