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天前
|
缓存 Devops jenkins
专家视角:构建可维护的测试架构与持续集成
【10月更文挑战第14天】在现代软件开发过程中,构建一个可维护且易于扩展的测试架构对于确保产品质量至关重要。本文将探讨如何设计这样的测试架构,并将单元测试无缝地融入持续集成(CI)流程之中。我们将讨论最佳实践、自动化测试部署、性能优化技巧以及如何管理和扩展日益增长的测试套件规模。
18 3
|
15天前
|
Web App开发 IDE 测试技术
自动化测试的利器:Selenium 框架深度解析
【10月更文挑战第2天】在软件开发的海洋中,自动化测试犹如一艘救生艇,让质量保证的过程更加高效与精准。本文将深入探索Selenium这一强大的自动化测试框架,从其架构到实际应用,带领读者领略自动化测试的魅力和力量。通过直观的示例和清晰的步骤,我们将一起学习如何利用Selenium来提升软件测试的效率和覆盖率。
|
9天前
|
机器学习/深度学习 并行计算 数据可视化
目标分类笔记(二): 利用PaddleClas的框架来完成多标签分类任务(从数据准备到训练测试部署的完整流程)
这篇文章介绍了如何使用PaddleClas框架完成多标签分类任务,包括数据准备、环境搭建、模型训练、预测、评估等完整流程。
30 0
目标分类笔记(二): 利用PaddleClas的框架来完成多标签分类任务(从数据准备到训练测试部署的完整流程)
|
9天前
|
机器学习/深度学习 数据采集 算法
目标分类笔记(一): 利用包含多个网络多种训练策略的框架来完成多目标分类任务(从数据准备到训练测试部署的完整流程)
这篇博客文章介绍了如何使用包含多个网络和多种训练策略的框架来完成多目标分类任务,涵盖了从数据准备到训练、测试和部署的完整流程,并提供了相关代码和配置文件。
20 0
目标分类笔记(一): 利用包含多个网络多种训练策略的框架来完成多目标分类任务(从数据准备到训练测试部署的完整流程)
|
12天前
|
Web App开发 设计模式 测试技术
自动化测试框架的搭建与实践
【10月更文挑战第5天】本文将引导你理解自动化测试框架的重要性,并通过实际操作案例,展示如何从零开始搭建一个自动化测试框架。文章不仅涵盖理论,还提供具体的代码示例和操作步骤,确保读者能够获得实用技能,提升软件质量保障的效率和效果。
|
12天前
|
SQL 消息中间件 大数据
大数据-159 Apache Kylin 构建Cube 准备和测试数据(一)
大数据-159 Apache Kylin 构建Cube 准备和测试数据(一)
30 1
|
12天前
|
SQL 大数据 Apache
大数据-159 Apache Kylin 构建Cube 准备和测试数据(二)
大数据-159 Apache Kylin 构建Cube 准备和测试数据(二)
43 1
|
13天前
|
Web App开发 敏捷开发 Java
自动化测试框架的选择与应用
【10月更文挑战第4天】在软件开发的海洋中,自动化测试如同一艘航船,帮助开发者们快速穿越测试的波涛。选择适合项目的自动化测试框架,是确保航行顺利的关键。本文将探讨如何根据项目需求选择合适的自动化测试框架,并分享一些实用的代码示例,助你启航。
|
14天前
|
测试技术 持续交付 数据安全/隐私保护
软件测试的艺术与科学:探索自动化测试框架
【10月更文挑战第3天】在软件开发的海洋里,自动化测试犹如一艘航船,引领着项目向着质量的彼岸航行。本文将揭开自动化测试框架的神秘面纱,从理论到实践,深入浅出地探讨如何构建和运用这一工具,确保软件产品的稳定性和可靠性。我们将通过一个实际案例,展示自动化测试框架的搭建过程,以及它如何在提高测试效率、减少人力成本等方面发挥巨大作用。无论你是测试新手还是资深开发者,这篇文章都将为你提供宝贵的知识和启示。
|
15天前
|
敏捷开发 jenkins 测试技术
自动化测试框架的设计与实践
【10月更文挑战第2天】在软件开发周期中,测试阶段扮演着至关重要的角色。随着敏捷开发和持续集成的流行,自动化测试已成为确保软件质量和加快交付速度的关键工具。本文将深入探讨自动化测试框架的设计原则、组件选择、以及实现过程。通过实际案例分析,我们不仅展示了如何构建一个健壮的自动化测试框架,还讨论了如何克服常见问题,并提出了优化策略,以帮助读者更好地理解自动化测试的价值和实施细节。