单元测试实践

简介: 工欲善其事,必先利其器. 单元测试三剑客: - TestNg:单元测试框架 - AssertJ:断言工具 - Jmockit:mock工具

说在前面的话:

就像阿里规约里提到, 单元测试需要满足的AIR原则 :

  • A:Automatic(自动化)
  • I:Independent(独立性)
  • R:Repeatable(可重复)
    image

工欲善其事,必先利其器. 单元测试三剑客:

  • TestNg:单元测试框架
  • AssertJ:断言工具
  • Jmockit:mock工具

TestNg


testNg是个unit test/sut框架, 支持很多功能。但本篇文章重点不是介绍testNg,简单提一下我觉得比较有用的功能

  • Group:测试用例分组,根据业务/逻辑分组,以更小的粒度来执行case.
  • Parallel:并行执行,可以配置多个线程来执行case.需要注意并发问题.

    <suite name="My suite" thread-count="10" parallel="classes">
     <test name="mocking">
         <packages>
             <package name="com.hz.constantine.jmockit.slideshare.mocking"/>
         </packages>
       </test>
     <test name="faking">
         <packages>
             <package name="com.hz.constantine.jmockit.slideshare.faking"/>
         </packages>
     </test>
     <test name="testng">
         <packages>
             <package name="com.hz.constantine.jmockit.slideshare.testng"/>
         </packages>
     </test>
    </suite>
  • Listener:通过监听器集成自定义的功能
  • DataProvider:测试用例和测试数据分离

    static final String expectData = DataProviderTest.class.getSimpleName();
    static final class DataProvider{
       @org.testng.annotations.DataProvider(name = "str")
       public static Object[][] provide(){
           return new Object[][]{{expectData}};
       }
    }
    @Test(dataProvider = "str",dataProviderClass = DataProvider.class)
    public void dataProviderTest(String data){
       Assert.assertEquals(data,expectData);
    }
  • Timeout/ExpectExceptions:支持用例执行超时 和 异常

    @Test(timeOut = 5,expectedExceptions = {ThreadTimeoutException.class,NullPointerException.class})
    public void timeout(){
       try {
           Thread.sleep(10);
       } catch (InterruptedException e) {
       }
    }

    Tips:附上TestNg Tutorial, http://testng.org/doc/documentation-main.html

TestNg 集成Jmockit


image

  • Java instrumentation:开发者可以构建一个独立于应用程序的代理程序,监测和协助运行在JVM上的程序,虚拟机级别的AOP实现
  • TestNg Listener: TestNg Listener特性提供开发者扩展TestNg的能力.

Jmockit


在jmockit的世界里,它提供两套不同的语法和api. 分别是mocking和faking.下面分别针对这两套做详细的说明

-1- mocking

注解

image

特性
  • Expectations.代表一组调用关联到当期的case.
  • Record-Replay-Verify Mode.
  • Record: 预准备依赖和数据.
  • Replay:执行业务.
  • Verify:校验.
  • RecordingResult
  • FlexibleArgumentTest
  • Delegate表达式
  • Caputring: 用在Verification里.
  • CasCadeMock: 级联Mock

其中最重要的是Record-Replay-Verify Mode ,三段式的表述方式。即

  1. Record: 记录,即定义数据、并mock相关的依赖.
  2. Replay:回放,即执行被测试的业务逻辑.
  3. Verify:校验,即校验逻辑是否正确.
    废话不多说,直接上代码:

    @Test(expectedExceptions = MissingInvocation.class)
    public void recordReplyVerifyNotInOrder() {
       //Record
       ClassUnderTest classUnderTestInstance = newClassUnderTestInstance();
       final String data = this.getClass().getSimpleName();
       new Expectations(classUnderTestInstance.getEye(), classUnderTestInstance.getRepository()) {
           {
               classUnderTestInstance.getEye().find();
               result = data;
               classUnderTestInstance.getRepository().insert(data);
               times = 1;
           }
       };
       //Replay
       classUnderTestInstance.action();
       //Verify
       new VerificationsInOrder(){
           {
               classUnderTestInstance.getRepository().insert(data);
               classUnderTestInstance.getEye().find();
           }
       };
    }

其中 ClassUnderTest 是被测试类,依赖了Eye 和 Repository, 在Record阶段被定义了mocking.
其他特性的测试类,可以参看我的github: https://github.com/cscpswang/java-practice

-2- faking

  • Faking
  • unspecifiedFaking
  • Invocation Context
    第2个和第3个特性依然可以参看我的github,重点说明一下特性1:

1.定义一个被测试对象,一个echoServer(在io编程中,echoServer表示接受到任何消息不做处理,直接返回原消息)

       class EchoServer {
               private Dependency dependency=new Dependency();
               public String echo(String msg) {
                   return msg;
               }
               public String run(){
                  return dependency.run();
               }
       }

2.定义一个依赖类,这个类会在单测中被faking.

         class Dependency {
             public String run(){
                 return "dependency run";
             }
         }

3.case,测试EchoServer.

      public void applyFakesWithDependency(){
          final String msg = "i'm constantine";
          EchoServer echoServer = new EchoServer();
          final class DependencyMock extends MockUp<Dependency> {
              @Mock
              public String run(){
                  return msg;
              }
          }
          new DependencyMock();
          String actualMsg =  echoServer.run();
          Assert.assertEquals(actualMsg,msg);
      }

tips:

  1. spring 中使用faking api时泛型指定到具体的impl类.
  2. 被jdk 代理的类(如spring bean被aop),并不是实现类的实例. 所以要么基于接口mocking(需要mock接口的所有方法),要么使用faking.

小结:

Faking和Mocking是两套jmockit的api,在其官方文档,有下面一句话:

In particular, the use of both the Faking API and the Mocking API in the same test class should be viewed with suspicion, as it strongly indicates misuse.

image
我更偏爱使用Mocking api, 因为它的特性很酷。 但它不能mocking私有方法,这点有时会不太方便。

最后,如果你要下jmockit的源码,并希望研究,注意一个坑。由于jmockit基于java agent(instrumentation),你需要在你的classpath下放置一个jmockit-xxx.jar.

相关文章
|
4天前
|
敏捷开发 人工智能 Devops
探索自动化测试的高效策略与实践###
当今软件开发生命周期中,自动化测试已成为提升效率、保障质量的关键工具。本文深入剖析了自动化测试的核心价值,探讨了一系列高效策略,包括选择合适的自动化框架、设计可维护的测试脚本、集成持续集成/持续部署(CI/CD)流程,以及有效管理和维护测试用例库。通过具体案例分析,揭示了这些策略在实际应用中的成效,为软件测试人员提供了宝贵的经验分享和实践指导。 ###
|
3天前
|
机器学习/深度学习 人工智能 jenkins
软件测试中的自动化与持续集成实践
在快速迭代的软件开发过程中,自动化测试和持续集成(CI)是确保代码质量和加速产品上市的关键。本文探讨了自动化测试的重要性、常见的自动化测试工具以及如何将自动化测试整合到持续集成流程中,以提高软件测试的效率和可靠性。通过案例分析,展示了自动化测试和持续集成在实际项目中的应用效果,并提供了实施建议。
|
4天前
|
Java 测试技术 持续交付
探索自动化测试在软件开发中的关键作用与实践
在现代软件开发流程中,自动化测试已成为提升产品质量、加速交付速度的不可或缺的一环。本文深入探讨了自动化测试的重要性,分析了其在不同阶段的应用价值,并结合实际案例阐述了如何有效实施自动化测试策略,以期为读者提供一套可操作的实践指南。
|
29天前
|
Java 测试技术 开发者
初学者入门:掌握单元测试的基础与实践
【10月更文挑战第14天】单元测试是一种软件测试方法,它验证软件中的最小可测试单元——通常是单独的函数或类——是否按预期工作。单元测试的目标是确保每个模块在其自身范围内正确无误地运行。这些测试应该独立于其他模块,并且应该能够反复执行而不受外部环境的影响。
50 2
|
1月前
|
机器学习/深度学习 人工智能 监控
提升软件质量的关键路径:高效测试策略与实践在软件开发的宇宙中,每一行代码都如同星辰般璀璨,而将这些星辰编织成星系的过程,则依赖于严谨而高效的测试策略。本文将引领读者探索软件测试的奥秘,揭示如何通过精心设计的测试方案,不仅提升软件的性能与稳定性,还能加速产品上市的步伐,最终实现质量与效率的双重飞跃。
在软件工程的浩瀚星海中,测试不仅是发现缺陷的放大镜,更是保障软件质量的坚固防线。本文旨在探讨一种高效且创新的软件测试策略框架,它融合了传统方法的精髓与现代技术的突破,旨在为软件开发团队提供一套系统化、可执行性强的测试指引。我们将从测试规划的起点出发,沿着测试设计、执行、反馈再到持续优化的轨迹,逐步展开论述。每一步都强调实用性与前瞻性相结合,确保测试活动能够紧跟软件开发的步伐,及时适应变化,有效应对各种挑战。
|
1月前
|
测试技术 UED
软件测试的艺术与实践
【10月更文挑战第9天】 在数字时代的浪潮中,软件成为了我们生活和工作不可或缺的一部分。然而,高质量的软件背后,是无数测试工程师的默默付出。本文将通过深入浅出的方式,探讨如何进行高效的软件测试,确保软件产品的质量与稳定性。我们将一起揭开软件测试的神秘面纱,从基础理论到实际操作,一步步走进这个充满挑战与创造的世界。
|
4天前
|
Web App开发 敏捷开发 测试技术
探索自动化测试的奥秘:从理论到实践
【10月更文挑战第39天】在软件质量保障的战场上,自动化测试是提升效率和准确性的利器。本文将深入浅出地介绍自动化测试的基本概念、必要性以及如何实施自动化测试。我们将通过一个实际案例,展示如何利用流行的自动化测试工具Selenium进行网页测试,并分享一些实用的技巧和最佳实践。无论你是新手还是有经验的测试工程师,这篇文章都将为你提供宝贵的知识,帮助你在自动化测试的道路上更进一步。
|
4天前
|
敏捷开发 Java 测试技术
探索自动化测试:从理论到实践
【10月更文挑战第39天】在软件开发的海洋中,自动化测试是一艘能够带领团队高效航行的船只。本文将作为你的航海图,指引你理解自动化测试的核心概念,并分享一段实际的代码旅程,让你领略自动化测试的魅力和力量。准备好了吗?让我们启航!
|
9天前
|
测试技术 API Android开发
探索软件测试中的自动化框架选择与实践####
本文深入探讨了软件测试领域内,面对众多自动化测试框架时,如何依据项目特性和团队需求做出明智选择,并分享了实践中的有效策略与技巧。不同于传统摘要的概述方式,本文将直接以一段实践指南的形式,简述在选择自动化测试框架时应考虑的核心要素及推荐路径,旨在为读者提供即时可用的参考。 ####
|
20天前
|
机器学习/深度学习 人工智能 自然语言处理
探索软件测试的边界:从基础到高级的实践之旅
【10月更文挑战第21天】 在当今数字化时代,软件已成为我们生活和工作中不可或缺的一部分。随着技术的快速发展,对软件质量的要求也日益提高。本文旨在通过深入浅出的方式,带领读者踏上一场从基础到高级的软件测试实践之旅。我们将探讨软件测试的基本概念、重要性以及如何有效地进行测试规划和执行。通过具体案例分析,揭示常见错误及其解决方案,同时展望未来软件测试领域的发展趋势。无论你是软件开发新手还是经验丰富的测试工程师,这篇文章都将为你提供宝贵的见解和启发。
35 8