开发必备-----单元测试

简介: 你好看官,里面请!今天笔者讲的是单元测试。不懂或者觉得我写的有问题可以在评论区留言,我看到会及时回复。 注意:本文仅用于学习参考,不可用于商业用途,如需转载请跟我联系。

单元测试

如果觉得写的还可以,点个赞支持一下笔者呗!你的点赞和关注会让我更快更新哦。笔者会持续更新关于Java和大数据有关的文章。目前集中精力在更新java框架的内容。

1. 为什么要写单元测试

了解软件工程的人都知道,测试是软件开发阶段的最后一环,是保证软件质量的关键步骤(这也是为什么测试人员会被称作 QA 的原因)。只有通过严谨的测试,确保软件达到预期,才能够交付/上线。而单元测试是软件测试中与开发人员关系最紧密的一个环节。

刚刚接触单元测试的时候,看到它的名字我脑海中不由自主的蹦出一个疑问——测试不应该是专门的测试人员做的事情吗,跟开发人员有毛线关系呢?你是不是和我一样有过同样的疑问呢?后来随着对单元测试有了更深入的了解以后,发现写单元测试是每个开发者责无旁贷的事情。

曾经看到过一篇文章写单元测试的七种境界,可以看看自己在哪一层。七种境界大致如下:

  1. 以各种借口拒绝单元测试
  2. 尝试单元测试
  3. 单元测试一切
  4. 无法忍受脆弱的单元测试
  5. 发现了一种模拟 mocking 框架,并且乐于使用强制语义
  6. 模拟 mock 所有可能模拟 mocked 的对象
  7. 开始真正有效单元测试

通常来说,开发人员对代码进行一次改动,就应该进行一次单元测试。在编写完一个相对独立和完整的功能时,就应该为其编写对应的单元测试代码,而不是等功能开发完再去写单元测试,

不过在我有限的了解中,能够做到单元测试与业务代码同步开发的,真的是凤毛麟角了。能够在写完业务代码就去完成单元测试已经是不错的情况了,更为甚者等功能都上线了,再回过头来去补写单元测试。这种为了写单元测试而写单元测试的做法,完全背离的单元测试的初衷。不过这还不是最糟糕的,还有完全不写单元测试的呢。

单元测试理想的情况是,语句覆盖率可以达到 70% ;核心模块的语句覆盖率和分支覆盖率都要达到 100% 的标准(当年在一家日企工作时,就是这个标准)。

单元测试的意义

  • 对自己代码质量的一种保障
  • 为将来的重构保驾护航
  • 可以让新人更快熟悉代码

测试金字塔

还记得我们之前讲过的学习金字塔吗?今天我们聊一下另外一个金字塔——测试金字塔:

网络异常,图片无法展示
|

测试金字塔大致可以分为三层,由下到上分别是:

  • 单元测试
  • 服务测试
  • 用户界面测试

测试金字塔要表达的思想是:自下而上,成本越来越高(右边箭头),效率越来越低(左边箭头)。说得通俗一点就是,往上走事倍功半,往下走事半功倍。有一种说法,这三层的相对收益比(由上到下)为:1 : 2 : 7。但是目前很多公司还在 UI 层面拼命努力着。

结合我们之前讲过的学习金字塔,我们会发现一个非常有意思的现象——大多数人都在收益率最低的那一层拼命努力!想到这里,你有没有觉得后背发凉呢?有没有意识到自己曾经或者正在在某个低收益的层面拼命努力着呢?

2. 一个单元测试的自我修养

身为一个单元测试,要明确自己的定位,时时刻刻都要谨记——自己是一个单元测试。那么我们来看一下具备哪些素质才能称之为一个合格的单元测试呢?

  • 有明确的预期
  • 可重复运行
  • 独立且完整

有明确的预期,这个很好理解,我们的程序输入什么,将会输出什么,这是对于软件的最低要求;

可重复运行也不必多说了,如果我们的单元测试都是一锤子买卖,那也就没有什么写的必要了;

作为一个人,我们要有独立完整的自尊体系,同样,作为一个单元测试也要做到独立且完整。怎么理解呢?

举个例子,假如我们要写一个 Service 层的单元测试,那么运行这个单元测试的时候,就不能去真的访问数据库(因为与数据库打交道是 Dao 层的工作),这叫做独立。虽然不能访问数据库,但是还要保证整个流程可以正确完整的走通(你这不是强人所难吗?),这就是要完整。

那么我们如何做到独立且完整呢?答案就是—— Mock。市面上有很多的 Mock 框架,比如 Mockito、Jmock、easyMock 等。借助这些工具我们可以很轻松的 Mock 出我们想要的依赖。

独立且完整是单元测试的核心思想所在,单元二字将这种思想表达的淋漓尽致。在做单元测试时,我们默认当前功能的所有依赖都是可以正确执行的,我们的目的是测试当前功能的正确性,而这些 Mock 框架可以很好的将被测功能与其他功能隔离开。

3. JUnit

JUnit 是一个 Java 语言的单元测试框架,也是 Spring Boot 默认的单元测试工具,我们先来看一下 JUnit 的几个核心概念和常用注解。

JUnit 核心概念:

JUnit 的相关概念 说明
Test Class (测试类) 一个测试类包含一个或多个测试用例
Test Case (测试用例) 一个以 @Test 注释的方法称为 一个测试用例,测试用例必须存在于测试类中。
Assert
(断言)
定义想测试的条件,当条件成立时, Assert 方法保持沉默,条件不成立时则抛出异常
Suite
(测试组)
关联性紧密的一组测试可以定义为一个 Suite
Runner
(运行器)
单元测试的运行器(如 SpringRunner),JUnit4 是向后兼容的,可以运行 JUnit3 的测试

JUnit 常用注解:

注解 说明
@RunWith 指定运行器
@BeforeClass 作用于测试类类加载之前(静态方法)
@AfterClass 作用于测试类运行结束时(静态方法)
@Before 作用于测试用例运行前
@After 作用于测试用例运行后
@Test 作用于测试用例

4. 实战

OK,上面唠叨了那么多,是不是已经手痒了?接下来就来实践一把,过过瘾。要使用单元测试,我们首先需要添加依赖。不过,这次 Spring Boot 好像察觉到了我们的心思,在创建 Web 工程的时候,已经帮我们把 Test 的依赖添加好了,可见 Spring Boot 也是希望我们去写单元测试的。依赖引用如下:

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-test</artifactId>
  <scope>test</scope>
</dependency>

HelloController 类中按 Command + N (WIn 下是 Alt + Insert)或者鼠标右键单击选择 Generate.. 然后在弹出的菜单中选择 Test...

网络异常,图片无法展示
|

然后在接下来的对话框按如下图所示,勾选上对于的复选框,然后点击 OK :

网络异常,图片无法展示
|

然后去 src/test 目录下去找到我们创建的测试类,然后补充剩下的代码:

@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class HelloControllerTest {
    @Autowired
    private MockMvc mvc;
    @BeforeClass
    public static void beforeClass() {
        System.out.println("===before class===");
    }
    @Before
    public void setUp() throws Exception {
        System.out.println("===before method===");
    }
    @Test
    public void hello() throws Exception {
        MvcResult result = mvc.perform(get("/")
                                .param("name", "IMOOC")
                                .contentType(MediaType.APPLICATION_JSON))
                                    .andExpect(content()
                                    .string("Hello IMOOC"))
                                      .andReturn();
        System.out.println("==="+result.getResponse().getContentAsString()+"===");
    }
    @After
    public void tearDown() throws Exception {
        System.out.println("===after method===");
    }
    @AfterClass
    public static void afterClass() {
        System.out.println("===after class===");
    }
}

测试通过的运行效果:

...........
===before class===
01:16:18.853 [main] DEBUG org.springframework.t
test class [com.imooc.springboot.HelloControlle
...........
  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.1.5.RELEASE)
2019-06-17 01:16:19.602  INFO 66981 --- [      
...........
3.474 seconds (JVM running for 4.558)
===before method===
===Hello IMOOC===
===after method===
===after class===
...........

以上打印的内容进一步验证了上面几个注解的作用。

5. 总结

OK,我们一起学习了一下单元测试相关的内容。知道了 JUnit 的核心概念以及常用注解,并且做了一个 Spring Boot + JUnit 的实例,进一步加深了对于单元测试以及 JUnit 的理解。

相关文章
|
2月前
|
缓存 运维 数据库
【测试人员兼职指南】利用专业技能:如何从测试转向开发赚钱
本文分享了作者作为测试人员如何利用专业技能转向开发来兼职赚钱的经验,包括分析和解决登录页面跳转、避免重复账号注册、用户登录后首页显示用户名以及添加退出功能等问题,并提供了Django项目中使用sqlite3数据库和后台管理的扩展技巧。
47 1
【测试人员兼职指南】利用专业技能:如何从测试转向开发赚钱
|
2月前
|
Java 测试技术 开发者
在软件开发中,测试至关重要,尤以单元测试和集成测试为然
在软件开发中,测试至关重要,尤以单元测试和集成测试为然。单元测试聚焦于Java中的类或方法等最小单元,确保其独立功能正确无误,及早发现问题。集成测试则着眼于模块间的交互,验证整体协作效能。为实现高效测试,需编写可测性强的代码,并选用JUnit等合适框架。同时,合理规划测试场景与利用Spring等工具也必不可少。遵循最佳实践,可提升测试质量,保障Java应用稳健前行。
38 1
|
11天前
|
测试技术 持续交付 UED
软件测试的艺术与科学:平衡创新与质量的探索在软件开发的波澜壮阔中,软件测试如同灯塔,指引着产品质量的方向。本文旨在深入探讨软件测试的核心价值,通过分析其在现代软件工程中的应用,揭示其背后的艺术性与科学性,并探讨如何在追求技术创新的同时确保产品的高质量标准。
软件测试不仅仅是技术活动,它融合了创造力和方法论,是软件开发过程中不可或缺的一环。本文首先概述了软件测试的重要性及其在项目生命周期中的角色,随后详细讨论了测试用例设计的创新方法、自动化测试的策略与挑战,以及如何通过持续集成/持续部署(CI/CD)流程优化产品质量。最后,文章强调了团队间沟通在确保测试有效性中的关键作用,并通过案例分析展示了这些原则在实践中的应用。
30 1
|
9天前
|
测试技术 UED 开发者
软件测试的艺术:从代码审查到用户反馈的全景探索在软件开发的宇宙中,测试是那颗确保星系正常运转的暗物质。它或许不总是站在聚光灯下,但无疑是支撑整个系统稳定性与可靠性的基石。《软件测试的艺术:从代码审查到用户反馈的全景探索》一文,旨在揭开软件测试这一神秘面纱,通过深入浅出的方式,引领读者穿梭于测试的各个环节,从细微处着眼,至宏观视角俯瞰,全方位解析如何打造无懈可击的软件产品。
本文以“软件测试的艺术”为核心,创新性地将技术深度与通俗易懂的语言风格相结合,绘制了一幅从代码审查到用户反馈全过程的测试蓝图。不同于常规摘要的枯燥概述,这里更像是一段旅程的预告片,承诺带领读者经历一场从微观世界到宏观视野的探索之旅,揭示每一个测试环节背后的哲学与实践智慧,让即便是非专业人士也能领略到软件测试的魅力所在,并从中获取实用的启示。
|
2月前
|
测试技术 API
软件测试:Postman 工具的使用。开发及测试均需要掌握的测试工具
这篇文章详细介绍了Postman工具的各个模块功能,包括创建请求、集合、环境、自动化测试等,并解释了如何使用Postman进行GET、POST、PUT和DELETE等常见HTTP请求的测试。
|
2月前
|
运维 Kubernetes 监控
|
2月前
|
机器学习/深度学习 人工智能
高于临床测试3倍准确率!剑桥大学开发AI模型,提前6年预测阿尔茨海默症
【8月更文挑战第9天】剑桥大学研发的人工智能模型在预测阿尔茨海默症方面取得突破,准确率比传统临床测试高三倍,能提前六年预测疾病发生。该模型基于深度学习,利用大量临床及神经影像数据识别生物标志物,预测准确性达80%。这一成果有望促进早期干预,改善患者预后,但仍需更大规模研究验证,并解决隐私与公平性等问题。论文已发表于《The Lancet》子刊。
38 6
|
2月前
|
测试技术 C# 开发者
“代码守护者:详解WPF开发中的单元测试策略与实践——从选择测试框架到编写模拟对象,全方位保障你的应用程序质量”
【8月更文挑战第31天】单元测试是确保软件质量的关键实践,尤其在复杂的WPF应用中更为重要。通过为每个小模块编写独立测试用例,可以验证代码的功能正确性并在早期发现错误。本文将介绍如何在WPF项目中引入单元测试,并通过具体示例演示其实施过程。首先选择合适的测试框架如NUnit或xUnit.net,并利用Moq模拟框架隔离外部依赖。接着,通过一个简单的WPF应用程序示例,展示如何模拟`IUserRepository`接口并验证`MainViewModel`加载用户数据的正确性。这有助于确保代码质量和未来的重构与扩展。
30 0
|
3月前
|
Java 编译器 运维
开发与运维测试问题之在JVM中方法区也被称之为什么如何解决
开发与运维测试问题之在JVM中方法区也被称之为什么如何解决
21 1
|
3月前
|
Java 开发者 运维
开发与运维测试问题之OpenJDK官方还未正式发布Compact Object Headers如何解决
开发与运维测试问题之OpenJDK官方还未正式发布Compact Object Headers如何解决
31 1
下一篇
无影云桌面