SpringMVC+MockMvc+dbUnit+cobertura构建测试框架(上)

简介: 本文基于SpringMVC搭建测试框架

通常情况我们可以借助easyMock及powerMock进行单元测试,但有时我们希望进行集成测试,可以通过发送http请求,测试某功能的完整性。


一般情况我们可以通过MockMvc模拟post或get请求,完成测试。但是当碰到delete或update进行测试时,容易对数据库造成污染,这时我们可以借助dbunit,对数据库进行测试数据的准备,测试完成后对事务进行回滚,方便下次测试。


1. maven集成测试组件


<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    <version>4.3.10.RELEASE</version>
</dependency>
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
    <scope>test</scope>
</dependency>
<!--数据库单元测试:消除单元测试对数据库的污染 start-->
<dependency>
    <groupId>com.github.springtestdbunit</groupId>
    <artifactId>spring-test-dbunit</artifactId>
    <version>1.1.0</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.dbunit</groupId>
    <artifactId>dbunit</artifactId>
    <version>2.4.9</version>
    <scope>test</scope>
</dependency>
<!--数据库单元测试:消除单元测试对数据库的污染 end-->


2. 定义测试基类,包括SpringMVC框架的集成,junit集成


@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@PropertySource("classpath:common.properties")
@TestPropertySource("classpath:common.properties")
@TestExecutionListeners({DependencyInjectionTestExecutionListener.class,
        DirtiesContextTestExecutionListener.class, TransactionalTestExecutionListener.class,
        ServletTestExecutionListener.class,
        DbUnitTestExecutionListener.class}) //@1
@ContextConfiguration(
        {"classpath*:/spring-context.xml", "classpath*:/spring-mvc.xml", "classpath*:/spring-mybatis.xml"})
@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)//@2
@Transactional 
public abstract class BaseSpringJUnitTest {
    public static Logger logger = LoggerFactory.getLogger(BaseSpringJUnitTest.class);
    @Autowired
    private UserInfoService userInfoService;
    private static boolean inited = false;
    /**
     * junit模拟用户名
     */
    private final static String USER_NAME = "admin";
    /**
     * junit模拟验证码
     */
    private final static String VALIDATE_CODE = "1234";
    /**
     * junit模拟密码
     */
    private final static String PASSWORD = "Admin123456";
    public static String token = "";
    protected MockMvc mockMvc; //@3
    @Before //@4
    public void setUp() throws Exception {
        if (!inited) {
            String code = userInfoService.getValidateKey().get("validateKey").toString();
            RedisUtils.set("validCode:" + code, VALIDATE_CODE);
            UserInfoRequestParams params = new UserInfoRequestParams();
            params.setLoginName(USER_NAME);
            params.setPassword(MD5Util.encoderHexByMd5(PASSWORD));
            params.setValidateKey(code);
            params.setValidateCode(VALIDATE_CODE);
            JSONOutputObject result = userInfoService.webLogin(params);
            token = result.get("token").toString();
            TestCase.assertEquals(RsmsConstant.RESULT_SUCCESS_CODE, result.get(RsmsConstant.RESULT_CODE));
            inited = true;
        }
    }
}


@1:ServletTestExecutionListener 用于设置spring web框架启动时的RequestContextHolder本地线程变量。我们的项目比较特殊,在service层中是通过RequestContextHolder获取httpRequest对象(并非通过controller透传),如果不设置,则在service中或者切面中无法获取到request对象


@2:添加事务回滚,避免对数据库的污染


@3:定义MockMvc对象,模拟客户端的http请求


@4:初始化登录信息,根据自身需要设置,有些集成测试场景可能需要登录信息


3.编写测试类


public class UserInfoControllerTest extends BaseSpringJUnitTest {
    @Test
    @DatabaseSetup(type = DatabaseOperation.INSERT, value = {"/data/user-info.xml"})//@1
    public void testDeleteUsers() throws Exception {
        mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();
        //@2
        String responseString = mockMvc.perform(post("/user/deleteUsers")
                .contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)
                .content("{\"idList\":10007}")
                .header("Current-Menu-Id", "102100")
                .header("Menu-Id", "102100")
                .accept(MediaType.ALL_VALUE)
                .header("token", token)
                .header("User-Agent", "Windows NT")
        ).andExpect(status().isOk())
                .andReturn().getResponse().getContentAsString();
        JSONObject jsonObject = JSONObject.parseObject(responseString);
        Assert.assertEquals(jsonObject.get("resultCode"), "0000");
    }
}


@1:准备测试数据,因为在测试时,如果不自己准备数据,依赖数据库数据,那么数据库数据有可能被其他人误删或者数据库做了迁移或更新之后,我们的测试用例将无法跑通。


@2:通过mockMvc发送http请求,并解析请求结果,判断测试结果的正确性


4.准备测试数据(resource/data/user_info.xml)


<?xml version="1.0" encoding="UTF-8" ?>
<dataset>
    <t_user_info id="10007" login_name="admin_junit" password="" salt="" user_name="admin_junit" user_name_spell=""
              user_name_initial="" eid="" cellphone="" company_id="200" org_id="200" position=""/>
    <t_user_role id="1000" user_id="10007" role_id="1" />
</dataset>


5.jenkins集成,并统计单元测试覆盖率


<!-- 统计junit覆盖率 -->
<plugin>
    <groupId>org.jacoco</groupId>
    <artifactId>jacoco-maven-plugin</artifactId>
    <version>0.8.1</version>
    <executions>
        <execution>
            <goals>
                <goal>prepare-agent</goal>
            </goals>
        </execution>
        <execution>
            <id>report</id>
            <phase>prepare-package</phase>
            <goals>
                <goal>report</goal>
            </goals>
        </execution>
    </executions>
</plugin>


jenkins添加普通的maven构建任务,设置好git地址


插件管理中安装jacoco插件


build项设置如下


Root POM           pom.xml


Goals and options  test -Dmaven.repo.local=/opt/repository


构建后操作添加:Record JaCoCo coverage report


统计结果效果如下


image.png

单元测试覆盖率统计


6.配置邮件发送


邮件发送本人是集成了cobertura(和jacoco共一样,都是用于覆盖率的统计)


pom集成

<!-- cobertura统计junit覆盖率 -->
          <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>cobertura-maven-plugin</artifactId>
                <version>2.7</version>
                <configuration>
                    <formats>
                        <format>html</format>
                        <format>xml</format>
                    </formats>
                </configuration>
            </plugin>


jenkins全局配置:jenkins->系统管理->系统设置


系统管理员地址:*********@qq.com


Extended E-mail Notification中配置如下


SMTP:smtp.qq.com


后缀@qq.com


点开高级


使用SMTP认证


用户名:*********@qq.com


密码:qq给的授权码(非邮箱的登录密码,授权码的获取:登录QQ邮箱:设置-SMTP设置-开启,需要发送短信,发送短信后,页面会显示授权码)


jenkins构建任务配置邮件发送


构建后操作:增加Editable Email Notification,点开高级,一定要设置triggers,否则无法触发


相关文章
|
3天前
|
人工智能 搜索推荐 数据管理
探索软件测试中的自动化测试框架选择与优化策略
本文深入探讨了在现代软件开发流程中,如何根据项目特性、团队技能和长期维护需求,精准选择合适的自动化测试框架。
37 8
|
9天前
|
人工智能 JavaScript 前端开发
自动化测试框架的演进与实践###
本文深入探讨了自动化测试框架从诞生至今的发展历程,重点分析了当前主流框架的优势与局限性,并结合实际案例,阐述了如何根据项目需求选择合适的自动化测试策略。文章还展望了未来自动化测试领域的技术趋势,为读者提供了宝贵的实践经验和前瞻性思考。 ###
|
4天前
|
安全 Ubuntu Linux
Metasploit Pro 4.22.6-2024111901 (Linux, Windows) - 专业渗透测试框架
Metasploit Pro 4.22.6-2024111901 (Linux, Windows) - 专业渗透测试框架
25 9
Metasploit Pro 4.22.6-2024111901 (Linux, Windows) - 专业渗透测试框架
|
12天前
|
Java 测试技术 API
探索软件测试中的自动化框架选择####
在当今快节奏的软件开发周期中,自动化测试已成为确保产品质量与加速产品迭代的关键策略。本文深入剖析了自动化测试的核心价值,对比分析了市场上主流的自动化测试框架,旨在为项目团队提供选型时的考量因素及实践指南,助力高效构建适应未来变化的自动化测试体系。 ####
|
8天前
|
Java 测试技术 API
探索软件测试中的自动化测试框架
本文深入探讨了自动化测试在软件开发中的重要性,并详细介绍了几种流行的自动化测试框架。通过比较它们的优缺点和适用场景,旨在为读者提供选择合适自动化测试工具的参考依据。
|
11天前
|
jenkins 测试技术 持续交付
自动化测试框架的搭建与实践
在软件开发领域,自动化测试是提升开发效率、确保软件质量的关键手段。本文将引导读者理解自动化测试的重要性,并介绍如何搭建一个基本的自动化测试框架。通过具体示例和步骤,我们将探索如何有效实施自动化测试策略,以实现软件开发流程的优化。
36 7
|
8天前
|
数据管理 jenkins 测试技术
自动化测试框架的设计与实现
在软件开发周期中,测试是确保产品质量的关键步骤。本文通过介绍自动化测试框架的设计原则、组件构成以及实现方法,旨在指导读者构建高效、可靠的自动化测试系统。文章不仅探讨了自动化测试的必要性和优势,还详细描述了框架搭建的具体步骤,包括工具选择、脚本开发、执行策略及结果分析等。此外,文章还强调了持续集成环境下自动化测试的重要性,并提供了实际案例分析,以帮助读者更好地理解和应用自动化测试框架。
|
9天前
|
监控 测试技术 定位技术
探索软件测试中的自动化测试框架选择与实施###
本文不概述传统意义上的摘要内容,而是直接以一段对话形式引入,旨在激发读者兴趣。想象一下,你是一名勇敢的探险家,面前摆满了各式各样的自动化测试工具地图,每张地图都指向未知的宝藏——高效、精准的软件测试领域。我们将一起踏上这段旅程,探讨如何根据项目特性选择合适的自动化测试框架,并分享实施过程中的关键步骤与避坑指南。 ###
19 4
|
8天前
|
敏捷开发 测试技术 持续交付
自动化测试之美:从零开始搭建你的Python测试框架
在软件开发的马拉松赛道上,自动化测试是那个能让你保持节奏、避免跌宕起伏的神奇小助手。本文将带你走进自动化测试的世界,用Python这把钥匙,解锁高效、可靠的测试框架之门。你将学会如何步步为营,构建属于自己的测试庇护所,让代码质量成为晨跑时清新的空气,而不是雾霾中的忧虑。让我们一起摆脱手动测试的繁琐枷锁,拥抱自动化带来的自由吧!
|
9天前
|
测试技术 持续交付 数据安全/隐私保护
软件测试的艺术与科学:探索自动化测试框架
在软件开发的世界中,测试是确保产品质量的关键环节。本文将深入探讨自动化测试框架的重要性和实现方法,旨在为读者揭示如何通过自动化测试提升软件测试效率和准确性。我们将从测试的基本概念出发,逐步引导读者了解自动化测试框架的设计和实施过程,以及如何选择合适的工具来支持测试活动。文章不仅提供理论知识,还将分享实用的代码示例,帮助读者将理论应用于实践。无论你是测试新手还是经验丰富的开发者,这篇文章都将为你打开一扇通往更高效、更可靠软件测试的大门。
13 1