51Testing软件测试论坛

 找回密码
 (注-册)加入51Testing

QQ登录

只需一步,快速开始

微信登录,快人一步

手机号码,快捷登录

查看: 844|回复: 1
打印 上一主题 下一主题

[转贴] 提高单元测试效率的几点优化

[复制链接]
  • TA的每日心情
    无聊
    昨天 09:05
  • 签到天数: 1050 天

    连续签到: 1 天

    [LV.10]测试总司令

    跳转到指定楼层
    1#
    发表于 2022-6-28 10:08:41 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
    单元测试(Unit Testing)又称为模块测试, 是针对程序模块(软件设计的最小单位)来进行正确性检验的测试工作。 程序单元是应用的最小可测试部件。简单来说,就是测试数据的稳定性是否达到程序的预期。谈到测试,我们为什么要对程序进行测试呢?测试会为程序带来什么好处呢?
      我们日常开发时可能在不经意间写错,如果等到最后阶段去检验项目成果时,发现有错误,这时候我们很难找到Bug的源头在哪里。我们都知道,有可能一处出错会导致步步错的情况。
      测试就在我们的上述说法中,显得尤为重要,当我们做完项目的一个小模块,先去测试一下这个小模块是否正确或达到预期,如果错误或者没有达到预期就需要反复修改,直到正确或达到预期,也就是使用了单元测试。
      单元测试的编码规范一般涉及到以下内容:
      类名: 定义测试类,类名是由被测试类名Test构成。例如:CalculatorTest;
      包名:定义的测试类需要放在xxx.xxx.xxx.test包中。例如:package com.autodrive.test;
      方法名: 测试方法的方法名有两种定义方式test测试方法和测试方法。例如:testCheck和check;
      返回值: 因为我们的方法只是在类中测试,可以独立运行,所以不需要处理任何返回值,所以这里使用void。例如:public void check();
      参数列表: 因为我们的方法是用来测试的,至于参数列表的传入是没有必要的。我们在测试的时候自行传入需要的参数测试即可。所以在此参数列表为空。例如:例如:public void check();
      @Test注解: 测试是需要运行来完成的。如果我们只有一个main方法,显然在结构上还是需要我们去注释掉测试过的。解决此问题这里我们需要在测试方法上方加@Test注解来完成测试,只要是加该注解的方法,可以单独运行此方法来完成测试。
      IDEA快捷导入Junit4、5: 使用IDEA的小伙伴,你们的福音来了。我们可以先创建测试类和方法,然后在测试方法上方加入@Test注解,此时IDEA显示的@Test注解是飘红的,这时候我们使用Alt + Enter组合键来打开导入Junit单元测试列表,然后再选择Junit4或者Junit5确定。
      在SpringBoot往往存在单元测试用到如下的注解与写法:
    1. @RunWith(SpringRunner.class)
    2. @SpringBootTest(classes = Application.class)
    3. @Transactional
    4. @Rollback(true) // 事务自动回滚,默认是true。可以不写
    5. public class NoticeServiceTest {
    6.     @Autowired
    7.     private NoticeService noticeService;
    8.     @Test
    9.     public void sayHello() {
    10.         helloService.sayHello("zhangsan");
    11.     }
    12. }
    复制代码
    在上面这个例子中,@SpringBootTest启动了SpringBoot环境,扫描应用程序的spring配置,并构建完整的Spring Context,其classes = Application.class启动了整个项目。通过@SpringBootTest我们可以指定启动类,或者给@SpringBootTest的参数webEnvironment赋值为SpringBootTest.WebEnvironment.RANDOM_PORT,这样就会启动web容器,并监听一个随机的端口,同时,为我们自动装配一个TestRestTemplate类型的bean来辅助我们发送测试请求。
      @Transactional表明调用数据库并作事务处理;@RunWith(SpringRunner.class)声明在Spring的环境中进行单元测试,这样Spring的相关注解就会被识别并起效,而@Autowired启动了Spring。
      当项目使用了@Component注解,在SpringBoot项目启动的时候就会跟着实例化/启动,这个@Component注解的类里有多线程方法,随着启动类中定义的ApplicationStartup类启动了,那么在你执行单元测试的时候,由于多线程任务的影响,就可能对你的数据库造成了数据修改,即使你使用了事务回滚注解。
      高效的单元测试应该脱离数据库,以满足快速启动完成测试、支持服务间调用的需求。可以通过如下几点来对上述例子进行优化:
      1. 启动Spring会让run->Junit Test的时候程序变慢,这是每次运行单元测试都很慢的原因之一。然后单元测试是只针对某一个类的方法来测,启动Spring很多时候是多余的,所以我们只需要对应的实体类实例就够了。在需要注入bean的时候,我们直接new。
    1. private NoticeService noticeService = new NoticeService();
    复制代码
     2. @SpringBootTest是在SpringBoot项目上使用的,它在@SpringBootContextLoader的基础上,配置文件属性的读取,会读取、解析一些项目配置文件,还会连接数据库,然后如果启动类又带有别的启动类、@Component、多线程等,而单元测试很多时候可以避免启动SpringBoot,减少启动所耗费的大量时间,即不使用@SpringBootTest注解。
      3. 应当使用断言来判断单元测试结果是否符合预期。
      4. @RunWith 在JUnit中有很多个Runner,他们负责调用具体测试代码,每一个Runner都有各自的特殊功能,你要根据需要选择不同的Runner来运行你的测试代码,且一般都是使用SpringRunner.class。如果我们只是简单的做普通Java测试,不涉及Spring Web项目,可以省略@RunWith注解,这样系统会自动使用默认Runner来运行你的代码。
      5.单元测试可以通过Mock数据的方式避开对数据库的调用,减少很多数据库连接的时间。Mock是模拟一切操作数据库的步骤,不执行任何[url=]SQL[/url],我们直接模拟这句操作数据库的代码执行会是成功的,而且可以模拟任何返回值,主要有两个注解。只要是本地的,自己写的bean,都可以使用@MockBean,它会把所有操作数据库的方法模拟。如果是没有返回值的方法,我们就可以不管。如果是有返回值的方法,我们可以给它返回各自我们需要模拟的值。如果是我们本地,调用别的公司,别的地方给我们写好的接口,不是操作我们自己的数据库,是我们写好入参,别人给我们返回值,我们就用@SpyBean。
      Mock所需依赖如下:
    1. <dependency>
    2. <groupId>org.springframework.boot</groupId>
    3. <artifactId>spring-boot-starter-test</artifactId>
    4. <scope>test</scope>
    5. </dependency>
    复制代码
    通过以上优化,可以大大缩短我们单测的时间,提高我们开发效率。



    分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
    收藏收藏
    回复

    使用道具 举报

  • TA的每日心情
    开心
    2022-6-25 16:45
  • 签到天数: 1 天

    连续签到: 1 天

    [LV.1]测试小兵

    2#
    发表于 2022-6-28 12:27:32 | 只看该作者
    厉害,大佬们真多
    回复 支持 反对

    使用道具 举报

    本版积分规则

    关闭

    站长推荐上一条 /1 下一条

    小黑屋|手机版|Archiver|51Testing软件测试网 ( 沪ICP备05003035号 关于我们

    GMT+8, 2024-11-22 15:26 , Processed in 0.066580 second(s), 23 queries .

    Powered by Discuz! X3.2

    © 2001-2024 Comsenz Inc.

    快速回复 返回顶部 返回列表