名著阅读 > Spring Boot实战 > 5.3 用CLI运行测试 >

5.3 用CLI运行测试

测试是软件项目的重要组成部分,Spring Boot CLI当然没有忽略测试。因为基于CLI的应用程序并未涉及传统的构建系统,所以CLI提供了一个test命令来运行测试。

在试验test命令前,你先要写一个测试。测试可以放在项目中的任何位置。我建议将其与主要组件分开放置,最好放在一个子目录里。这个子目录的名字随意。我在这里将其命名为tests:

$ mkdir tests

  

在tests目录里,创建一个名为ReadingListControllerTest.groovy的新Groovy脚本,编写针对ReadingListController的测试。代码清单5-3是个简单的测试,测试控制器能否正确处理HTTP GET请求。

代码清单5-3 ReadingListController的Groovy测试

import org.springframework.test.web.servlet.MockMvc
import static
    org.springframework.test.web.servlet.setup.MockMvcBuilders.*
import static org.springframework.test.web.servlet.request.
                                             MockMvcRequestBuilders.*
import static org.springframework.test.web.servlet.result.
                                             MockMvcResultMatchers.*
import static org.mockito.Mockito.*

class ReadingListControllerTest {

  @Test
  void shouldReturnReadingListFromRepository {
    List<Book> expectedList = new ArrayList<Book>
    expectedList.add(new Book(
        id: 1,
        reader: \"Craig\",
        isbn: \"9781617292545\",
        title: \"Spring Boot in Action\",
        author: \"Craig Walls\",
        description: \"Spring Boot in Action is ...\"
      ))

  def mockRepo = mock(ReadingListRepository.class)    ←---模拟 ReadingListRepository
  when(mockRepo.findByReader(\"Craig\")).thenReturn(expectedList)

  def controller =
      new ReadingListController(readingListRepository: mockRepo)

  MockMvc mvc = standaloneSetup(controller).build
  mvc.perform(get(\"/\"))                   ←---执行并测试GET请求
    .andExpect(view.name(\"readingList\"))
    .andExpect(model.attribute(\"books\", expectedList))
  }

}

  

如你所见,这就是个简单的JUnit测试,使用了Spring的模拟MVC测试支持功能,对控制器发起GET请求。最先设置的是ReadingListRepository的一个模拟实现,它会返回一个包含单一Book项的列表。随后,测试创建了一个ReadingListController实例,将模拟仓库注入readingListRepository属性。最后,配置了一个MockMvc对象,发起GET请求,对期望的视图名称和模型内容进行断言。

但是,此处运行测试要比说明测试更重要。使用CLI的test命令,可以像下面这样在命令行里执行测试:

$ spring test tests/ReadingListControllerTest.groovy

  

本例中,我明确选中了ReadingListControllerTest作为要运行的测试。如果tests/目录里有多个测试,你想要全部运行,可以在test命令中指定目录名:

$ spring test tests

  

如果你倾向于编写Spock说明而非JUnit测试,那么你一定会很高兴,因为CLI的test命令也可以运行Spock说明,代码清单5-4的ReadingListControllerSpec就演示了这一功能。

代码清单5-4 测试ReadingListController的Spock说明

import org.springframework.test.web.servlet.MockMvc
import static
    org.springframework.test.web.servlet.setup.MockMvcBuilders.*
import static org.springframework.test.web.servlet.request.
                                             MockMvcRequestBuilders.*
import static org.springframework.test.web.servlet.result.
                                             MockMvcResultMatchers.*
import static org.mockito.Mockito.*

class ReadingListControllerSpec extends Specification {

  MockMvc mockMvc
  List<Book> expectedList

  def setup {
    expectedList = new ArrayList<Book>
    expectedList.add(new Book(
      id: 1,
      reader: \"Craig\",
      isbn: \"9781617292545\",
      title: \"Spring Boot in Action\",
      author: \"Craig Walls\",
      description: \"Spring Boot in Action is ...\"
    ))

    def mockRepo = mock(ReadingListRepository.class)     ←---模拟的ReadingListRepository
    when(mockRepo.findByReader(\"Craig\")).thenReturn(expectedList)

    def controller =
        new ReadingListController(readingListRepository: mockRepo)
    mockMvc = standaloneSetup(controller).build
  }

  def \"Should put list returned from repository into model\" {
    when:
      def response = mockMvc.perform(get(\"/\"))    ←---执行GET请求

    then:
      response.andExpect(view.name(\"readingList\"))
              .andExpect(model.attribute(\"books\", expectedList))     ←---测试结果
  }

}

  

ReadingListControllerSpec只是简单地把 ReadingListControllerTest从JUnit测试翻译成了Spock说明。如你所见,它只是直白地表述了这么一个过程。对“/”出现GET请求时,响应中应该包含名为readingList的视图。模型里的books键所对应的就是期待的图书列表。

Spock说明也可以通过spring test tests来运行ReadingListControllerSpec。运行方式和基于JUnit的测试如出一辙。

一旦写好代码,通过了全部测试,你就该部署项目了。让我们来看看Spring Boot CLI是如何帮助产生一个可部署的产物的。