当前位置: 移动技术网 > IT编程>开发语言>Java > Spring入门(十四):Spring MVC控制器的2种测试方法

Spring入门(十四):Spring MVC控制器的2种测试方法

2019年09月26日  | 移动技术网IT编程  | 我要评论

作为一名研发人员,不管你愿不愿意对自己的代码进行测试,都得承认测试对于研发质量保证的重要性,这也就是为什么每个公司的技术部都需要质量控制部的原因,因为越早的发现代码的bug,成本越低,比如说,dev环境发现bug的成本要低于qa环境,qa环境发现bug的成本要低于prod环境,prod环境发现bug的成本最高,这也是每个研发人员最不愿意遇到但永远避不掉的现实。

虽然不能完全避免,但我们可以对自己的代码进行充分的测试,降低bug出现的几率。

所以, 本篇博客我们主要讲解下spring mvc控制器的3种测试方法:

  1. 部署项目后测试
  2. 借助junit和spring test框架测试
  3. 借助swaggerui接口文档测试

1. 部署项目后测试

在前2篇博客中,我们采取的就是这种测试方式,即将项目打成war包,部署到tomcat中,运行项目后, 借助浏览器或者postman等工具对控制器进行测试。

如果是get请求,可以使用浏览器或者postman测试。

如果是post、put、delete等请求,可以使用postman进行测试。

有兴趣的同学,可以看下之前的2篇博客:

spring入门(十二):spring mvc使用讲解

spring入门(十三):spring mvc常用注解讲解

2. 借助junit和spring test框架测试

上面的方法虽然可以进行测试,但每次都打包、部署、运行项目、测试,显然很不方便,不过强大的spring通过spring test框架对集成测试提供了支持,接下来我们讲解具体的使用方法。

因为我们的spring项目是通过maven管理的,所以它的项目结构有以下4个目录:

  1. src/main/java:项目代码
  2. src/main/resources:项目资源
  3. src/test/java:测试代码
  4. src/test/resources:测试资源(该目录默认没有生成,有需要的可以自己新建)

也就是说,我们可以将我们的测试代码放在src/test/java目录下,不过截止目前,我们还并未在该目录添加任何测试代码。

2.1 添加依赖

在添加测试代码前,我们需要在pom.xml中添加如下依赖:

<dependency>
    <groupid>org.springframework</groupid>
    <artifactid>spring-test</artifactid>
    <version>4.3.18.release</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupid>junit</groupid>
    <artifactid>junit</artifactid>
    <version>4.12</version>
    <scope>test</scope>
</dependency>

也许有的同学会好奇,为啥本次添加的依赖增加了<scope>test</scope>, 它有啥作用呢?

带着这个疑问,我们编译下项目,发现原本编译正常的代码竟然编译报错了:

报错信息提示程序包org.junit不存在,可我们明明添加了该依赖啊,这是为什么呢,会不会和<scope>test</scope>有关呢?

恭喜你,猜对了,确实和<scope>test</scope>有关,如果你此时将该项移除,项目编译就不报错了(不过建议不要移除)。

这是因为,我们在之前添加测试代码时,都是放在src/main/java目录下的,现在依赖包增加了<scope>test</scope>,说明这些包的存活周期是在test周期,所以我们可以把之前的测试代码移到src/test/java目录下,如下所示:

再次编译项目,发现编译通过。

2.2 添加控制器

添加控制器前,新建demoservice如下所示:

package chapter05.service;

import org.springframework.stereotype.service;

@service
public class demoservice {
    public string saysomething() {
        return "hello";
    }
}

注意事项:该类添加了@service注解。

然后,新建控制器normalcontroller,它里面的方法返回jsp视图:

package chapter05.controller;

import chapter05.service.demoservice;
import org.springframework.beans.factory.annotation.autowired;
import org.springframework.stereotype.controller;
import org.springframework.ui.model;
import org.springframework.web.bind.annotation.requestmapping;

@controller
public class normalcontroller {
    @autowired
    private demoservice demoservice;

    @requestmapping("/normal")
    public string testpage(model model) {
        model.addattribute("msg", demoservice.saysomething());
        return "page";
    }
}

接着新建控制器myrestcontroller,它里面的方法直接返回信息:

package chapter05.controller;

import chapter05.service.demoservice;
import org.springframework.beans.factory.annotation.autowired;
import org.springframework.web.bind.annotation.requestmapping;
import org.springframework.web.bind.annotation.restcontroller;

@restcontroller
public class myrestcontroller {
    @autowired
    private demoservice demoservice;

    @requestmapping(value = "/testrest", produces = "text/plain;charset=utf-8")
    public string testrest() {
        return demoservice.saysomething();
    }
}

2.3 添加测试代码

在src/test/java下新建包chapter05,然后在其下面新建测试类testcontrollerintegrationtests如下所示:

package chapter05;

import chapter05.config.mymvcconfig;
import chapter05.service.demoservice;
import org.junit.before;
import org.junit.runner.runwith;
import org.springframework.beans.factory.annotation.autowired;
import org.springframework.test.context.contextconfiguration;
import org.springframework.test.context.junit4.springjunit4classrunner;
import org.springframework.test.context.web.webappconfiguration;
import org.springframework.test.web.servlet.mockmvc;
import org.springframework.test.web.servlet.setup.mockmvcbuilders;
import org.springframework.web.context.webapplicationcontext;

@runwith(springjunit4classrunner.class)
@contextconfiguration(classes = {mymvcconfig.class})
@webappconfiguration("src/main/resources")
public class testcontrollerintegrationtests {
    private mockmvc mockmvc;

    @autowired
    private demoservice demoservice;

    @autowired
    private webapplicationcontext webapplicationcontext;

    @before
    public void setup() {
        this.mockmvc = mockmvcbuilders.webappcontextsetup(this.webapplicationcontext).build();
    }
}

代码讲解:

@runwith(springjunit4classrunner.class)用于在junit环境下提供spring test框架的功能。

@contextconfiguration(classes = {mymvcconfig.class})用来加载配置applicationcontext,其中classes属性用来加载配置类,mymvcconfig配置类的代码如下所示:

package chapter05.config;

import org.springframework.context.annotation.bean;
import org.springframework.context.annotation.componentscan;
import org.springframework.context.annotation.configuration;
import org.springframework.web.servlet.config.annotation.enablewebmvc;
import org.springframework.web.servlet.view.internalresourceviewresolver;
import org.springframework.web.servlet.view.jstlview;

/**
 * spring mvc配置
 */
@configuration
@enablewebmvc
@componentscan("chapter05")
public class mymvcconfig {
    /**
     * 视图解析器配置
     *
     * @return
     */
    @bean
    public internalresourceviewresolver viewresolver() {
        internalresourceviewresolver viewresolver = new internalresourceviewresolver();

        viewresolver.setprefix("/web-inf/classes/views/");
        viewresolver.setsuffix(".jsp");
        viewresolver.setviewclass(jstlview.class);

        return viewresolver;
    }
}

@webappconfiguration("src/main/resources") 用来声明加载的applicationcontext是一个webapplicationcontext,它的属性指定的是web资源的位置,默认为src/main/webapp,这里我们修改成

src/main/resources。

mockmvc用来模拟mvc对象,它在添加了@before注解的setup()中,通过this.mockmvc = mockmvcbuilders.webappcontextsetup(this.webapplicationcontext).build();进行初始化赋值。

然后往测试类中添加如下测试代码:

@test
public void testnormalcontroller() throws exception {
    mockmvc.perform(get("/normal"))
            .andexpect(status().isok())
            .andexpect(view().name("page"))
            .andexpect(forwardedurl("/web-inf/classes/views/page.jsp"))
            .andexpect(model().attribute("msg", demoservice.saysomething()));
}

代码解释:

perform(get("/normal"))用来模拟向/normal发起get请求,

andexpect(status().isok())预期返回的状态码为200,

andexpect(view().name("page"))预期视图的逻辑名称为page,

andexpect(forwardedurl("/web-inf/classes/views/page.jsp"))预期视图的真正路径是/web-inf/classes/views/page.jsp",

andexpect(model().attribute("msg", demoservice.saysomething()))预期model里有一个msg属性,它的值是demoservice.saysomething()的返回值hello。

执行该测试方法,测试通过:

最后往测试类中添加如下测试代码:

@test
public void testrestcontroller() throws exception {
    mockmvc.perform(get("/testrest"))
            .andexpect(status().isok())
            .andexpect(content().contenttype("text/plain;charset=utf-8"))
            .andexpect(content().string(demoservice.saysomething()));
}

代码解释:

perform(get("/testrest"))用来模拟向/testrest发起get请求,

andexpect(status().isok())预期返回的状态码为200,

andexpect(content().contenttype("text/plain;charset=utf-8"))预期返回值的媒体类型为text/plain;charset=utf-8,

andexpect(content().string(demoservice.saysomething()))预期返回值的内容为demoservice.saysomething()的返回值hello。

执行该测试方法,测试通过:

3. 源码及参考

源码地址:,欢迎下载。

craig walls 《spring实战(第4版)》

汪云飞《java ee开发的颠覆者:spring boot实战》

4. 最后

欢迎扫码关注微信公众号:「申城异乡人」,定期分享java技术干货,让我们一起进步。

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网