对编写的代码进行单元测试_编写数据访问代码测试–单元测试是浪费

对编写的代码进行单元测试

几年前,我是为我的数据访问代码编写单元测试的那些开发人员之一。 我正在孤立地测试所有内容,我对自己感到非常满意。 老实说,我认为自己做得很好。 哦,男孩,我错了! 这篇博客文章描述了为什么我们不应该为数据访问代码编写单元测试,并解释为什么我们应该用集成测试代替单元测试。 让我们开始吧。

单元测试错误问题的答案

我们为数据访问代码编写测试,因为我们想知道它可以按预期工作。 换句话说,我们想找到这些问题的答案:

  1. 是否将正确的数据存储到使用的数据库?
  2. 我们的数据库查询是否返回正确的数据?

单元测试可以帮助我们找到想要的答案吗? 嗯, 单元测试的最基本规则之一是单元测试不应使用诸如数据库之类的外部系统 。 此规则不适用于当前情况,因为存储正确信息和返回正确查询结果的责任由我们的数据访问代码和使用的数据库划分。 例如,当我们的应用程序执行单个数据库查询时,职责划分如下:

  • 负责创建执行的数据库查询的数据访问代码。
  • 数据库负责执行数据库查询,并将查询结果返回给数据访问代码。

问题是,如果我们将数据访问代码与数据库隔离,则可以测试数据访问代码是否创建了“正确的”查询,但是我们无法确保所创建的查询返回正确的查询结果。 这就是为什么单元测试不能帮助我们找到想要的答案的原因

告诫故事:Mo是问题的一部分

有段时间我为数据访问代码编写了单元测试。 当时我有两个规则:

  1. 每段代码都必须单独进行测试。
  2. 让我们使用模拟。

我当时在一个使用Spring Data JPA的项目中工作,而动态查询是使用JPA条件查询构建的。 如果您不熟悉Spring Data JPA,则可能需要阅读Spring Data JPA教程的第四部分,该教程解释了如何使用Spring Data JPA创建JPA条件查询 。 无论如何,我创建了一个规范构建器类来构建Specification <Person>对象。 创建Specification <Person>对象之后,将其转发给我的Spring Data JPA存储库,该存储库执行查询并返回查询结果。 规范构建器类的源代码如下所示:

import org.springframework.data.jpa.domain.Specification;import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;public class PersonSpecifications {public static Specification<Person> lastNameIsLike(final String searchTerm) {return new Specification<Person>() {@Overridepublic Predicate toPredicate(Root<Person> personRoot, CriteriaQuery<?> query, CriteriaBuilder cb) {String likePattern = getLikePattern(searchTerm);              return cb.like(cb.lower(personRoot.<String>get(Person_.lastName)), likePattern);}private String getLikePattern(final String searchTerm) {return searchTerm.toLowerCase() + "%";}};}
}

让我们看一下“验证”规范构建器类创建“正确”查询的测试代码。 请记住,我是按照自己的规则编写该测试类的,这意味着结果应该很棒。 PersonSpecificationsTest类的源代码如下所示:

import org.junit.Before;
import org.junit.Test;
import org.springframework.data.jpa.domain.Specification;import javax.persistence.criteria.*;import static junit.framework.Assert.assertEquals;
import static org.mockito.Mockito.*;public class PersonSpecificationsTest {private static final String SEARCH_TERM = "Foo";private static final String SEARCH_TERM_LIKE_PATTERN = "foo%";private CriteriaBuilder criteriaBuilderMock;private CriteriaQuery criteriaQueryMock;private Root<Person> personRootMock;@Beforepublic void setUp() {criteriaBuilderMock = mock(CriteriaBuilder.class);criteriaQueryMock = mock(CriteriaQuery.class);personRootMock = mock(Root.class);}@Testpublic void lastNameIsLike() {Path lastNamePathMock = mock(Path.class);       when(personRootMock.get(Person_.lastName)).thenReturn(lastNamePathMock);Expression lastNameToLowerExpressionMock = mock(Expression.class);when(criteriaBuilderMock.lower(lastNamePathMock)).thenReturn(lastNameToLowerExpressionMock);Predicate lastNameIsLikePredicateMock = mock(Predicate.class);when(criteriaBuilderMock.like(lastNameToLowerExpressionMock, SEARCH_TERM_LIKE_PATTERN)).thenReturn(lastNameIsLikePredicateMock);Specification<Person> actual = PersonSpecifications.lastNameIsLike(SEARCH_TERM);Predicate actualPredicate = actual.toPredicate(personRootMock, criteriaQueryMock, criteriaBuilderMock);verify(personRootMock, times(1)).get(Person_.lastName);verifyNoMoreInteractions(personRootMock);verify(criteriaBuilderMock, times(1)).lower(lastNamePathMock);verify(criteriaBuilderMock, times(1)).like(lastNameToLowerExpressionMock, SEARCH_TERM_LIKE_PATTERN);verifyNoMoreInteractions(criteriaBuilderMock);verifyZeroInteractions(criteriaQueryMock, lastNamePathMock, lastNameIsLikePredicateMock);assertEquals(lastNameIsLikePredicateMock, actualPredicate);}
}

这有道理吗? 没有! 我必须承认,此测试对任何人都没有价值,应该尽快删除。 此测试有三个主要问题:

  • 它不能帮助我们确保数据库查询返回正确的结果。
  • 很难理解并使情况更糟,它描述了查询的构建方式,但没有描述查询应返回的内容。
  • 这样的测试很难编写和维护。

事实是,此单元测试是不应编写的测试的教科书示例。 它对我们没有任何价值,但我们仍然必须维护它。 因此, 这是浪费! 但是,如果我们为数据访问代码编写单元测试,就会发生这种情况。 我们最终得到了一个测试套件,无法测试正确的东西。

数据访问测试正确完成

我是单元测试的忠实拥护者,但是在某些情况下,它并不是工作的最佳工具。 这是其中一种情况。 数据访问代码与使用的数据存储有非常密切的关系。 这种关系是如此紧密,以至于没有数据存储,数据访问代码本身就没有用。 这就是为什么将我们的数据访问代码与二手数据存储区分开来是没有意义的。 解决这个问题很简单。 如果我们要为数据访问代码编写全面的测试,则必须将数据访问代码与使用的数据存储一起进行测试。 这意味着我们必须忘记单元测试并开始编写集成测试 。 我们必须了解,只有集成测试才能验证

  • 我们的数据访问代码创建正确的数据库查询。
  • 我们的数据库返回正确的查询结果。

如果您想知道如何为Spring支持的存储库编写集成测试,则应该阅读我的博客文章,标题为Spring Data JPA教程:集成测试 。 它描述了如何为Spring Data JPA存储库编写集成测试。 但是,在为使用关系数据库的任何存储库编写集成测试时,可以使用相同的技术。 例如, 为测试“ 将jOOQ与Spring结合使用”教程中的示例应用程序而编写的集成测试使用该博客文章中描述的技术。

摘要

这篇博客文章教会了我们两件事:

  • 我们了解到,单元测试无法帮助我们验证数据访问代码是否正常运行,因为我们无法确保将正确的数据插入到数据存储中或查询返回正确的结果。
  • 我们了解到,应该使用集成测试来测试数据访问代码,因为数据访问代码和使用的数据存储之间的关系是如此紧密,以至于没有必要将它们分开。

只剩下一个问题:您是否还在为数据访问代码编写单元测试?

翻译自: https://www.javacodegeeks.com/2014/07/writing-tests-for-data-access-code-unit-tests-are-waste.html

对编写的代码进行单元测试

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/340478.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

用php模拟斗地主发牌,php模拟实现斗地主发牌

本文实例为大家分享了php实现斗地主发牌的具体代码&#xff0c;供大家参考&#xff0c;具体内容如下闲来无聊&#xff0c;就写了这个方法&#xff0c;也算是熟悉下php的数组操作&#xff0c;还请各位大神多指教。$arr 数组&#xff0c;好像有点问题&#xff0c;应该 2>"…

python odoo_Odoo开发教程20-使用 Python 虚拟环境安装 Odoo第二讲

配置插件(add-ons)路径社区贡献的插件可以打包成 Python 库&#xff0c;发布到 Python 包索引(PyPI -Python Package Index)&#xff0c;然后像其它库一样使用 pip 安装。为了能使用这一方法&#xff0c;Odoo 自动添加了 sitepackages/文件夹至插件配置路径&#xff0c;用于安装…

如何在AWS EC2实例上部署Spring Boot应用程序

你好朋友&#xff0c; 在本教程中&#xff0c;我们将看到如何在AWS EC2实例上部署Spring Boot应用程序。 这是我们将要执行的步骤。 1.使用Spring Boot Initialiser创建一个Spring Boot项目。 2.创建一个休息端点&#xff0c;部署后我们可以访问 3.启动EC2实例 4.将我们的…

ps -ef grep java解释,ps -ef | grep java(示例代码)

ps命令将某个进程显示出来grep命令是查找中间的|是管道命令 是指ps命令与grep同时执行PS是LINUX下最常用的也是非常强大的进程查看命令grep命令是查找&#xff0c;是一种强大的文本搜索工具&#xff0c;它能使用正则表达式搜索文本&#xff0c;并把匹配的行打印出来。grep全称是…

python世界第一语言_Java 跌落神坛!Python 正式登顶世界第一编程语言

编程语言流行指数(PYPL)排行榜近日公布了2019年2月份榜单。在最新一期榜单上&#xff0c;Python的份额高达26.42&#xff05;&#xff0c;稳居第一&#xff0c;并且猛增5.2%&#xff0c;同时成为增长势头最好的语言。而被挤到第二的Java&#xff0c;目前份额为21.2&#xff05;…

成为Java流大师–第3部分:终端操作

比尔盖茨曾经说过&#xff1a;“我选择一个懒惰的人去做一件困难的事情&#xff0c;因为一个懒惰的人会找到一个简单的方法来做。” 关于流&#xff0c;没有什么比这更真实了。 在本文中&#xff0c;您将学习Stream如何通过在调用终端操作之前不对源元素执行任何计算来避免不必…

python选项卡中文详细说明_pycharm窗口选项卡管理

1、主题我们已经注意到Pycharm的主编辑框是基于窗口选项卡机制显示的&#xff0c;Pycharm选项卡多种多样&#xff0c;这里我们将详细介绍这种选项卡机制。2、激活的选项卡每当我们打开一个Python文件时open a file for editing&#xff0c;它都会对应打开一个选项卡窗口&#x…

和至少为k的最短子数组 python_和至少为k的最短子数组

// 单调栈// 维护一个具有栈单调性的队列&#xff0c;跟动态规划不一样的是时间复杂度为O(n)// queue[i]中存放着前缀和// 我们知道因为负数的存在&#xff0c;所以队列不是单调增长的&#xff0c;但是不单调的其实对我们没有用// 因为肯定可以找到比它短的(因此我们移除比)// …

matlab多径信道模型,基于matlab的无线多径信道建模与仿真分析

基于matlab的无线多径信道建模与仿真分析 基于MATLAB的无线多径信道建模与仿真分析 摘 要:对于无线通信, 衰落是影响系统性能的重要因素, 而不同形式的衰落对于信号产生的影响 也不相同。本文在阐述移动多径信道特性的基础上, 建立了不同信道模型下多径时延效应的计算 机仿真模…

c 遍历文件 递归遍历_将递归文件系统遍历转换为流

c 遍历文件 递归遍历在学习编程的时候&#xff0c;回溯到Turbo Pascal的时代&#xff0c;我设法使用FindFirst &#xff0c; FindNext和FindClose函数在目录中列出文件。 首先&#xff0c;我想出了一个打印给定目录内容的过程。 您可以想象我为能够真正从自身调用该过程以递归遍…

净迁移人口预测程序python_高质量深度学习模型, 一键模型预测,迁移学习很简单...

飞桨(PaddlePaddle)核心框架Paddle Fluid v1.5已经发布&#xff0c;而作为其关键工具&#xff0c;用来迁移学习的PaddleHub也进行了全面更新&#xff0c;正式发布了1.0版本。全新的PaddleHub模型和任务更加丰富&#xff0c;为用户提供了覆盖 文本 、 图像 和 视频 三大领域八大…

您的JVM是否泄漏文件描述符-像我的一样?

前言&#xff1a;此处描述的两个问题是在一年前发现并修复的。 本文仅用作历史证明&#xff0c;也是有关解决Java中文件描述符泄漏的初学者指南。 在Ultra ESB中&#xff0c;我们使用内存RAM磁盘文件缓存来进行快速且无垃圾的有效负载处理。 一段时间以前&#xff0c;我们在共…

matlab中degrees,Convert degrees-minutes-seconds to degrees

Angle in degrees-minutes-seconds representation, specified as ann-by-3 real-valued matrix. Each row specifies oneangle, with the format [D M S]:D contains the “degrees” elementand must be integer-valued.M contains the “minutes” elementand must be integ…

螺旋桨设计软件_欧洲斥巨资研发的A400M螺旋桨运输机,为啥就没人买啊?| 图说...

A400M是欧洲自行设计、研制和生产的新一代军用运输机&#xff0c;也是欧盟国家进行合作的最大的武器联合研制项目。A400M最大的特点&#xff0c;就是其标志性的8叶弯刀螺旋桨。A400M也是20世纪后服役的为数不多的几个使用涡轮旋桨发动机的军用运输机之一。A400M曾在系列电影《碟…

python5个功能_5个常用的定制Python功能代码

文章来源&#xff1a;淘论文网 发布者&#xff1a;毕业设计浏览量:一、随机数生成>>> import random #导入Python内置的随机模块>>> num random.randint(1,1000) #生成1-1000之间的伪随机数二、读文件>>> f open(c:\1.txt,r)>>> lin…

php链接远程socket,php使用socket获取远程图片

步骤&#xff1a;1&#xff0c;匹配URL中的主机名和文件部分2&#xff0c;创建socket并连接到目标服务器3&#xff0c;构造HTTP请求并发送4&#xff0c;读取HTTP响应并解析5&#xff0c;保存内容到文件并关闭socket连接代码实现如下&#xff1a;/** 使用socket获取远程资源(网页…

JAR文件句柄:烦恼后清理!

在Ultra ESB中&#xff0c;我们使用特殊的热交换类加载器 &#xff0c;该加载器使我们可以按需重新加载Java类。 这使我们能够从字面上热交换我们的部署单元 -加载&#xff0c;卸载&#xff0c;使用更新的类重新加载&#xff0c;以及正常地逐步退出-无需重启JVM。 Windows&…

大气校正后的ndvi_Sentinel2 L1C下载、大气校正、重采样

点击蓝字关注我哦1.基本信息(成像仪/重访周期/波段数/分辨率)哨兵2号是高分辨率多光谱成像卫星&#xff0c;携带一枚多光谱成像仪(MSI)&#xff0c;用于陆地监测&#xff0c;可提供植被、土壤和水覆盖、内陆水路及海岸区域等图像&#xff0c;分为2A和2B两颗卫星,哨兵&#xff0…

hello python的代码,python基础教程之Hello World!

Python命令行假设你已经安装好了Python, 那么在Linux命令行输入:代码如下:$python将直接进入python。然后在命令行提示符>>>后面输入:代码如下:>>>print(Hello World!)可以看到&#xff0c;随后在屏幕上输出:代码如下:Hello World!print是一个常用函数&#…

python3 线程隔离_Python的线程隔离实现方法

前段时间看了下flask的源码&#xff0c;对于这样一个轻量级的web框架是怎样支持多线程的感到非常好奇&#xff0c;于是深入了解了一番。flask是依赖werkeug来实现线程间的隔离的&#xff0c;而werkeug最后又使用到了python的内置模块locals来承载数据&#xff0c;看不如写&…