测试SpringBoot中Web应用程序

要恰当好处的测试一个Web应用程序,不仅仅是对基础逻辑方法的测试,还应该包含处理的Post、Get请求的情况以及测试表单域绑定到实体参数的情况,即我们需要投入一些实际的HTTP请求,确认它能够正确的处理这些请求。

SpringBoot中有两个可选方案能够实现这种测试:

  • Spring Mock MVC:能在一个近似真实的模拟Servlet容器里测试控制器,而不用实际启动应用服务器。
  • Web集成测试:在嵌入式Servlet容器(Jetty、Tomcat)里启动应用程序,在真正的服务器里执行测试。

一.模拟SpringMVC(Spring Mock MVC)

Spring的Mock MVC框架模拟了SpringMVC的很多功能,几乎和运行的Servlet容器里面的程序一样

要在测试中设置Mock MVC,可以用MockMvcBuilders,它提供了两个静态方法可以是实现:

  1. standaloneSetup():构建一个Mock MVC,提供一个或多个手工初始化并注入我们要测试的控制器(需要手工初始化并注入要测试的控制器
  2. webAppContextSetup():使用Spring应用程序的上下文来构建Mock MVC,该上下文可以包含一个或多个配置好的控制器(基于WebApplicationContext的实例,由Spring加载控制器和其依赖)
    代码如下:
@RunWith(SpringRunner.class)
@SpringBootTest
public class BoyControllerTest {
    @Autowired
    private WebApplicationContext wac;//注入WebApplicationContext

    private MockMvc mockMvc;

    /**
     * 设置MockMvc
     */
    @Before
    public void setup() {
        mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();
    }
}

现在我们有了一个Mock MVC,已经可以开始测试方法了,代码如下:

方法中使用了很多静态方法,包括Spring的MockMvcRequestBuilders和MockMvcResultMatchers里的静态方法,还有Hamcrest库的Matchers里的静态方法

为了方便这里先添加一些静态的import:

import static org.hamcrest.Matchers.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
	@Test
    public void whenQuerySuccess() throws Exception{
        mockMvc.perform(get("/boy")  						//	向/Boy发起一个Get请求
                .contentType(MediaType.APPLICATION_JSON_UTF8))
                .andExpect(status().isOk())						//希望请求处理成功(isOk()会判断HTTP 200响应码)
                .andExpect(view().name("readingList"))		//返回视图的逻辑名称为是否为readingList
                .andExpect(model().attributeExists("users"))      //断定模型中是否包含一个users的属性
                .andExpect(model().attribute("users",notNullValue()));   //断定模型中users的属性不为空
    }

    @Test
    public void whenGetInfoSuccess() throws Exception{
        String result=mockMvc.perform(get("/boy/1"))
                .andExpect(status().isOk())
                .andReturn().getResponse().getContentAsString();    //获取返回的信息
        System.out.println("result:"+result);
    }

    @Test
    public void whenGetInfo() throws Exception{
        mockMvc.perform(get("/user/a")
                    .contentType(MediaType.APPLICATION_JSON_UTF8))
                    .andExpect(status().is4xxClientError());
    }

二.模拟SpringMVC(RestTemplate)

在真实的服务器里启动应用程序,用真实的Web浏览器访问它,这样比使用模拟的测试引擎更能展现应用程序在用户端的行为,但真实的Web浏览器在真实的服务器上运行测试会很麻烦,而部署到Tomcat或Jetty里配置又不方便,并且几乎不能相互隔离运行。SpringBoot中支持将Tomcat和Jetty这样的嵌入式Servlet容器作为运行中的应用程序的一部分,运用相同的机制,在测试过程中用嵌入式Servlet容器来启动应用程序,这就用到了SpringBoot中的@WebIntegrationTest注解。

@WebIntegrationTest注解:申明希望SpringBoot为测试创建应用程序上下文,并且还启动一个嵌入式的Servlet容器,一旦程序运行在嵌入式容器中,便可以发起真实的http请求

代码如下:

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class SimpleWebTest {
    @Autowired
    private TestRestTemplate restTemplate;
    @Test
    public void getUsers(){
        MultiValueMap multiValueMap = new LinkedMultiValueMap();
        multiValueMap.add("id",1);
        String result=restTemplate.getForObject("/boy/{id}",String.class,1);//get请求
        System.out.println(result);
    }
}

三.使用Selenium测试页面

使用Selenium测试页面:

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class SeleniumWebTest {
    private static FirefoxDriver browser;

    @Value("${local.server.port}")
    private int port;

    @BeforeClass
    public static void openBrowser(){
        browser=new FirefoxDriver();
        browser.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
    }

    @Test
    public void addUserToEmptyList(){
        String baseUrl="http://localhost:"+port+"/demo/boy";
        browser.get(baseUrl);
        System.out.println(browser.findElementByTagName("div").getText());
        Assert.assertEquals("you have no users in your list",browser.findElementByTagName("div").getText());
    }

    @AfterClass
    public static void closeBrowser(){
        browser.quit();
    }
}

运行后发现错误,代码如下:

java.lang.IllegalStateException: The path to the driver executable must be set by the webdriver.gecko.driver system property; for more information, see https://github.com/mozilla/geckodriver. The latest version can be downloaded from https://github.com/mozilla/geckodriver/releases
	at com.google.common.base.Preconditions.checkState(Preconditions.java:847)
	at org.openqa.selenium.remote.service.DriverService.findExecutable(DriverService.java:125)
	at org.openqa.selenium.firefox.GeckoDriverService.access$100(GeckoDriverService.java:43)
	at org.openqa.selenium.firefox.GeckoDriverService$Builder.findDefaultExecutable(GeckoDriverService.java:168)
	at org.openqa.selenium.remote.service.DriverService$Builder.build(DriverService.java:346)
	at org.openqa.selenium.firefox.FirefoxDriver.toExecutor(FirefoxDriver.java:168)
	at org.openqa.selenium.firefox.FirefoxDriver.<init>(FirefoxDriver.java:125)
	at org.openqa.selenium.firefox.FirefoxDriver.<init>(FirefoxDriver.java:103)
	at com.example.demo.SeleniumWebTest.openBrowser(SeleniumWebTest.java:25)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:497)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
	at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24)
	at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
	at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
	at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
	at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
	at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
	at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
	at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
java.lang.NullPointerException
	at com.example.demo.SeleniumWebTest.closeBrowser(SeleniumWebTest.java:39)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:497)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
	at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:33)
	at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
	at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
	at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
	at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
	at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)

因为在selenium和Firefox不兼容导致的,需要添加驱动,驱动下载地址:https://github.com/mozilla/geckodriver/releases
设置驱动位置

//设置firefox驱动路经  selenium3.0之后需设置 firefox版本要求大于48
System.setProperty("webdriver.gecko.driver","G:\\JavaTools\\driver\\geckodriver.exe");
browser=new FirefoxDriver();
browser.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值