集成测试还原数据库_项目学生:分片集成测试数据

集成测试还原数据库

这是Project Student的一部分。 其他职位包括带有Jersey的Webservice Client,带有Jersey的 Webservice Server , 业务层和带有Spring Data的持久性 。

到目前为止,所有集成测试都使用了一个内存嵌入式数据库,该数据库无法每次运行都保留信息。 当我们将REST服务器与“真实”数据库服务器完全集成时,这种情况会发生变化-剩余的测试数据将污染我们的开发或测试数据库。 一旦我们签入了运行集成测试代码的连续集成,这将是一个非常头疼的事情。

一种解决方案是以某种方式“分片”我们的集成测试数据,使我们的测试可以使用共享开发数据库而不会污染共享测试数据库或其他测试。 最简单的方法是将TestRun字段添加到所有对象。 “测试”数据将具有指示特定测试运行的值,“实时”数据将具有空值。

确切的时间表是

  1. 创建并持久保存一个TestRun对象
  2. 用适当的TestRun值创建测试对象
  3. 执行集成测试
  4. 删除测试对象
  5. 删除TestRun对象

TestRun表中的​​任何条目将是1)主动集成测试或2)引发未处理异常的集成测试失败(当然,这取决于事务管理器)。 重要的是要注意,即使事务管理器执行了回滚,我们也可以在引发意外异常后捕获数据库状态-这是对junit测试运行程序的简单扩展。

时间戳记和用户字段使您可以轻松地根据其年龄(例如,超过7天的任何测试)或运行测试的人员删除陈旧的测试数据。

TestablePersistentObject抽象基类

此更改从持久性级别开始,因此我们应该从持久性级别开始并逐步进行扩展。

我们首先使用测试运行值扩展PersistentObject抽象基类。

@MappedSuperclass
public abstract class TestablePersistentObject extends PersistentObject {private static final long serialVersionUID = 1L;private TestRun testRun;/*** Fetch testRun object. We use lazy fetching since we rarely care about the* contents of this object - we just want to ensure referential integrity to* an existing testRun object when persisting a TPO.* * @return*/@ManyToOne(fetch = FetchType.LAZY, optional = true)public TestRun getTestRun() {return testRun;}public void setTestRun(TestRun testRun) {this.testRun = testRun;}@Transientpublic boolean isTestData() {return testRun != null;}
}

TestRun类

TestRun类包含有关单个集成测试运行的标识信息。 它包含一个名称(默认情况下,该集成测试为classname#methodname()) ,测试的日期和时间以及运行该测试的用户的名称。 捕获其他信息将很容易。

测试对象列表为我们带来了两个重大胜利。 首先,如果需要(例如在发生意外异常之后),可以轻松捕获数据库的状态。 其次,级联删除使删除所有测试对象变得容易。

@XmlRootElement
@Entity
@Table(name = "test_run")
@AttributeOverride(name = "id", column = @Column(name = "test_run_pkey"))
public class TestRun extends PersistentObject {private static final long serialVersionUID = 1L;private String name;private Date testDate;private String user;private List<TestablePersistentObject> objects = Collections.emptyList();@Column(length = 80, unique = false, updatable = true)public String getName() {return name;}public void setName(String name) {this.name = name;}@Column(name = "test_date", nullable = false, updatable = false)@Temporal(TemporalType.TIMESTAMP)public Date getTestDate() {return testDate;}public void setTestDate(Date testDate) {this.testDate = testDate;}@Column(length = 40, unique = false, updatable = false)public String getUser() {return user;}public void setUser(String user) {this.user = user;}@OneToMany(cascade = CascadeType.ALL)public List<TestablePersistentObject> getObjects() {return objects;}public void setObjects(List<TestablePersistentObject> objects) {this.objects = objects;}/*** This is similar to standard prepersist method but we also set default* values for everything else.*/@PrePersistpublic void prepersist() {if (getCreationDate() == null) {setCreationDate(new Date());}if (getTestDate() == null) {setTestDate(new Date());}if (getUuid() == null) {setUuid(UUID.randomUUID().toString());}if (getUser() == null) {setUser(System.getProperty("user.name"));}if (name == null) {setName("test run " + getUuid());}}
}

TestRun类扩展了PersistentObject,而不是TestablePersistentObject,因为我们的其他集成测试将充分利用它。

Spring数据仓库

我们必须为每个存储库添加一种其他方法。

@Repository
public interface CourseRepository extends JpaRepository {List<Course> findCoursesByTestRun(TestRun testRun);....
}

服务介面

同样,我们必须为每个服务添加两个其他方法。

public interface CourseService {List<Course> findAllCourses();Course findCourseById(Integer id);Course findCourseByUuid(String uuid);Course createCourse(String name);Course updateCourse(Course course, String name);void deleteCourse(String uuid);// new method for testingCourse createCourseForTesting(String name, TestRun testRun);// new method for testingList<Course> findAllCoursesForTestRun(TestRun testRun);
}

我不会显示TestRunRepository,TestRunService接口或TestRunService实现,因为它们与我在最后几个博客条目中所描述的相同。

服务实施

我们必须对现有Service实施进行一次小的更改,并添加两种新方法。

@Service
public class CourseServiceImpl implements CourseService {@Resourceprivate TestRunService testRunService;/*** @see com.invariantproperties.sandbox.student.business.CourseService#*      findAllCourses()*/@Transactional(readOnly = true)@Overridepublic List<Course> findAllCourses() {List<Course> courses = null;try {courses = courseRepository.findCoursesByTestRun(null);} catch (DataAccessException e) {if (!(e instanceof UnitTestException)) {log.info("error loading list of courses: " + e.getMessage(), e);}throw new PersistenceException("unable to get list of courses.", e);}return courses;}/*** @see com.invariantproperties.sandbox.student.business.CourseService#*      findAllCoursesForTestRun(com.invariantproperties.sandbox.student.common.TestRun)*/@Transactional(readOnly = true)@Overridepublic List<Course> findAllCoursesForTestRun(TestRun testRun) {List<Course> courses = null;try {courses = courseRepository.findCoursesByTestRun(testRun);} catch (DataAccessException e) {if (!(e instanceof UnitTestException)) {log.info("error loading list of courses: " + e.getMessage(), e);}throw new PersistenceException("unable to get list of courses.", e);}return courses;}/*** @see com.invariantproperties.sandbox.student.business.CourseService#*      createCourseForTesting(java.lang.String,*      com.invariantproperties.sandbox.student.common.TestRun)*/@Transactional@Overridepublic Course createCourseForTesting(String name, TestRun testRun) {final Course course = new Course();course.setName(name);course.setTestUuid(testRun.getTestUuid());Course actual = null;try {actual = courseRepository.saveAndFlush(course);} catch (DataAccessException e) {if (!(e instanceof UnitTestException)) {log.info("internal error retrieving course: " + name, e);}throw new PersistenceException("unable to create course", e);}return actual;}
}

CourseServiceIntegrationTest

我们对集成测试进行了一些更改。 我们只需更改一种测试方法,因为它是唯一实际创建测试对象的方法。 其余方法是不需要测试数据的查询。

请注意,我们更改名称值以确保其唯一性。 这是解决唯一性约束(例如电子邮件地址)的一种方法。

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { BusinessApplicationContext.class, TestBusinessApplicationContext.class,TestPersistenceJpaConfig.class })
@Transactional
@TransactionConfiguration(defaultRollback = true)
public class CourseServiceIntegrationTest {@Resourceprivate CourseService dao;@Resourceprivate TestRunService testService;@Testpublic void testCourseLifecycle() throws Exception {final TestRun testRun = testService.createTestRun();final String name = "Calculus 101 : " + testRun.getUuid();final Course expected = new Course();expected.setName(name);assertNull(expected.getId());// create courseCourse actual = dao.createCourseForTesting(name, testRun);expected.setId(actual.getId());expected.setUuid(actual.getUuid());expected.setCreationDate(actual.getCreationDate());assertThat(expected, equalTo(actual));assertNotNull(actual.getUuid());assertNotNull(actual.getCreationDate());// get course by idactual = dao.findCourseById(expected.getId());assertThat(expected, equalTo(actual));// get course by uuidactual = dao.findCourseByUuid(expected.getUuid());assertThat(expected, equalTo(actual));// get all coursesfinal List<Course> courses = dao.findCoursesByTestRun(testRun);assertTrue(courses.contains(actual));// update courseexpected.setName("Calculus 102 : " + testRun.getUuid());actual = dao.updateCourse(actual, expected.getName());assertThat(expected, equalTo(actual));// verify testRun.getObjectsfinal List<TestablePersistentObject> objects = testRun.getObjects();assertTrue(objects.contains(actual));// delete Coursedao.deleteCourse(expected.getUuid());try {dao.findCourseByUuid(expected.getUuid());fail("exception expected");} catch (ObjectNotFoundException e) {// expected}testService.deleteTestRun(testRun.getUuid());}....
}

我们可以使用@Before@After透明地包装所有测试方法,但是许多测试不需要测试数据,而许多需要测试数据的测试则需要唯一的测试数据,例如,电子邮件地址。 在后一种情况下,我们按照上述方法折叠测试UUID。

REST Web服务服务器

REST Web服务需要在请求类中添加测试uuid,并在创建对象时添加一些逻辑以正确处理它。

REST Web服务不支持获取所有测试对象的列表。 “正确”的方法将是创建TestRun服务并响应/ get / {id}查询提供关联的对象。

@XmlRootElement
public class Name {private String name;private String testUuid;public String getName() {return name;}public void setName(String name) {this.name = name;}public String getTestUuid() {return testUuid;}public void setTestUuid(String testUuid) {this.testUuid = testUuid;}
}

现在,我们可以检查可选的testUuid字段并调用适当的create方法。

@Service
@Path("/course")
public class CourseResource extends AbstractResource {@Resourceprivate CourseService service;@Resourceprivate TestRunService testRunService;/*** Create a Course.* * @param req* @return*/@POST@Consumes({ MediaType.APPLICATION_JSON, MediaType.TEXT_XML })@Produces({ MediaType.APPLICATION_JSON, MediaType.TEXT_XML })public Response createCourse(Name req) {log.debug("CourseResource: createCourse()");final String name = req.getName();if ((name == null) || name.isEmpty()) {return Response.status(Status.BAD_REQUEST).entity("'name' is required'").build();}Response response = null;try {Course course = null;if (req.getTestUuid() != null) {TestRun testRun = testRunService.findTestRunByUuid(req.getTestUuid());if (testRun != null) {course = service.createCourseForTesting(name, testRun);} else {response = Response.status(Status.BAD_REQUEST).entity("unknown test UUID").build();}} else {course = service.createCourse(name);}if (course == null) {response = Response.status(Status.INTERNAL_SERVER_ERROR).build();} else {response = Response.created(URI.create(course.getUuid())).entity(scrubCourse(course)).build();}} catch (Exception e) {if (!(e instanceof UnitTestException)) {log.info("unhandled exception", e);}response = Response.status(Status.INTERNAL_SERVER_ERROR).build();}return response;}....
}

REST Web服务客户端

最后,REST服务器必须添加另一种方法。 客户端尚不支持获取所有测试对象的列表。

public interface CourseRestClient {/*** Create specific course for testing.* * @param name* @param testRun*/Course createCourseForTesting(String name, TestRun testRun);....
}

public class CourseRestClientImpl extends AbstractRestClientImpl implements CourseRestClient {/*** Create JSON string.* * @param name* @return*/String createJson(final String name, final TestRun testRun) {return String.format("{ \"name\": \"%s\", \"testUuid\": \"%s\" }", name, testRun.getTestUuid());}/*** @see com.invariantproperties.sandbox.student.webservice.client.CourseRestClient#createCourse(java.lang.String)*/@Overridepublic Course createCourseForTesting(final String name, final TestRun testRun) {if (name == null || name.isEmpty()) {throw new IllegalArgumentException("'name' is required");}if (testRun == null || testRun.getTestUuid() == null || testRun.getTestUuid().isEmpty()) {throw new IllegalArgumentException("'testRun' is required");}return createObject(createJson(name, testRun));}....
}

源代码

可从http://code.google.com/p/invariant-properties-blog/source/browse/student获取源代码。

澄清度

我认为在TestRun中不可能有@OneToMany到TestablePersistentObject,但是使用H2的集成测试成功了。 不幸的是,当我使用PostgreSQL数据库启动完全集成的Web服务时,这会引起问题。 我将代码留在上面,因为即使我们没有通用集合,也总是可以有一个教室列表,一个课程列表等。 但是,代码已从源代码控制的版本中删除。

更正

接口方法应该是findCourseByTestRun_Uuid() ,而不是findCourseByTestRun() 。 另一种方法是使用JPA标准查询-请参阅“ 项目学生:JPA标准查询” 。

参考: 项目学生:来自Invariant Properties博客的JCG合作伙伴 Bear Giles提供的分片集成测试数据 。

翻译自: https://www.javacodegeeks.com/2014/01/project-student-sharding-integration-test-data.html

集成测试还原数据库

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

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

相关文章

第十一届 蓝桥杯 单片机设计与开发项目 省赛 程序设计试题及源码

一、试题 1、 基本要求 1.1 使用大赛组委会提供的国信长天单片机竞赛实训平台,完成本试题的程序设计 与调试。 1.2 选手在程序设计与调试过程中,可参考组委会提供的“资源数据包”。 1.3 请注意: 程序编写、调试完成后选手应通过考试系统提交完整、可编译的 Keil 工程文件…

AWS:避免那些“神圣的法案”时刻的一些技巧

云非常棒&#xff1a;几乎100&#xff05;的可用性&#xff0c;几乎零维护&#xff0c;按需付费&#xff0c;最重要的是&#xff0c;它具有无限的可扩展性。 但是最后两个很容易把你咬回去&#xff0c;把那令人敬畏的事情变成一场噩梦。 有时您会看到类似的故事&#xff1a; …

樊昌信版通信原理期末复习第一章绪论

第1章 绪论 一、知识点梳理 1、通信的目的&#xff1a;传递消息中所包含的信息。 2、消息&#xff1a;是物质或精神状态的一种反映。 3、信息&#xff1a;是消息中包含的有效内容。 4、通信系统的一般模型 信源输入变换器&#xff1a;将非电物理量变成电信号。 发送设备&…

DC/DC开关电源设计

DC/DC开关电源设计视频讲解链接&#xff1a;https://www.bilibili.com/video/BV1Dv411y7jM?t156 一、电源概述 主要内容&#xff1a;线性稳压电源和开关稳压电源的概念理解 1、稳压电源&#xff08;stabilized voltage supply&#xff09;是能为负载提供稳定的交流电或直流…

jboss junit_使用junit-drools进行JBoss Drools单元测试

jboss junit最近&#xff0c;我一直在大量使用JBoss Drools进行项目。 我不是Drools专家-我也不太相信这个框架&#xff0c;或者可能不是只相信该项目中的特定用例-我发现很难为基于Drools的业务规则编写简单&#xff0c;可维护的单元测试 。 这就是junit-drools诞生的方式–简…

办公基础(小黑课堂)

F2&#xff1a;重命名 F4&#xff1a;重复上次操作 F5&#xff1a;刷新网页 F11&#xff1a;全屏显示网页 F12&#xff1a;另存为 笔记本中&#xff1a;Fn rand() 形成一段文字文本 lorem() 形成一段英文文本 CtrlP&#xff1a;打印 CtrlY&#xff1a;反撤销 Ctrl Shift N…

使用Spring Data JPA进行分页和排序

通过代码示例学习使用Spring Data JPA进行分页和排序 。 了解如何使用Springs PagingAndSortingRepository接口获取分页和排序结果。 1概述 在处理大量数据时&#xff0c;惰性处理通常是必不可少的。 即使服务返回了大量数据&#xff0c;消费者也不太可能使用它。 考虑一个购物…

【从3D点云生成平面图:一种空间划分方法】

文章目录 概要概述实验总结 概要 本文提出了一种从原始传感器数据自动重建室内环境平面图的新方法。现有的方法是通过检测角点并将它们连接起来&#xff0c;以平面图形的形式生成平面图&#xff0c;与此相反&#xff0c;本文采用了一种策略&#xff0c;将空间分解为多边形分区…

数字信号处理基础知识之DFT、DTFT、DFS、FFT基本概念扫盲

一、名词汇总 DFT&#xff1a;离散傅里叶变换&#xff08;Discrete Fourier Transform&#xff09;&#xff1b; DTFT&#xff1a;离散时间傅里叶变换&#xff08;Discrete-time Fourier Transform&#xff09;&#xff1b; DFS&#xff1a;离散傅里叶级数&#xff0c;又称离散…

Word学习笔记

文件菜单&#xff1a; 1、另存为快捷键&#xff1a;F12 论文打印时&#xff0c;保存为PDF格式 2、信息-保护文档-用密码进行加密 3、信息-检查文档 &#xff1a;批量删除相关内容 4、officeplus&#xff1a;模板下载 5、文件-选项-显示 7、文件-选项-校对&#xff1a;去掉波浪…

jersey put 服务_项目学生:带有Jersey的Web服务服务器

jersey put 服务这是Project Student的一部分。 其他职位包括带有Jersey的Webservice Client &#xff0c; 业务层和带有Spring Data的持久性 。 RESTful Web应用程序洋葱的第二层是Web服务服务器。 它应该是一个薄层&#xff0c;用于包装对业务层的调用&#xff0c;但不对其自…

数字基带传输学习笔记00引言

S0 引言 一、是什么 1、什么是数字基带信号&#xff1f; 未经调制的数字信号&#xff0c;所占据频谱从零频或很低频率开始 若信道中传输的是数字信号&#xff0c;则称为数字通信系统。这些信号包含丰富的低频分量&#xff0c;甚至直流分量&#xff0c;称为数字基带信号。 如…

如何在ADF中将参数传递给ActionListener

在某些情况下&#xff0c;需要将值传递给ADF Button的ActionListener。 可以由actionListeners调用的方法只有一个ActionEvent类型的参数。 因此&#xff0c;我将解释如何将参数传递给该bean方法&#xff0c;但是它在方法签名中仅包含一个参数ActionEvent。 我在页面上添加了…

计算机二级公共基础部分学习笔记

1、Rear指向队列最后一个元素的位置 Front指向队列第一个元素的前一个位置 RearFront&#xff0c;要么满&#xff0c;要么空&#xff1b;循环队列元素个数求法&#xff1b; 2、总节点数不同度节点数相加 总节点数度数*对应节点数和1 3、二叉树 前序&#xff1a;根-左-右 中序&…

【渝粤教育】电大中专新媒体营销实务 (9)作业 题库

1.新媒体在进行内容传播时&#xff0c;可以做到将文字、图片、视频等同时传播&#xff0c;呈现出&#xff08; &#xff09;的特点。 A.移动化 B.多元化 C.便捷性 错误 正确答案&#xff1a;左边查询 学生答案&#xff1a;A 2.第四媒体发展到宽带互联网阶段成为&#xff08; &a…

FPGA初学者入门相关概念知识点

一、基础入门 1、整体理解 简单来说&#xff0c;FPGA 就是“可反复编程的逻辑器件”。 ASIC 和 FPGA 就如同印刷品和白纸 ARM 虽然有很多外设&#xff0c;DSP 虽然具备强大的信号运算能力&#xff0c;但是&#xff0c;ARM 能做的&#xff0c;DSP 能做的&#xff0c;FPGA 一定…

java jpa 规范_Java:在JPA中使用规范模式

java jpa 规范本文是在Java中使用规范模式的简介。 我们还将看到如何将经典规范与JPA Criteria查询结合使用&#xff0c;以从关系数据库中检索对象。 在本文中&#xff0c;我们将使用以下Poll类作为创建规范的示例实体。 它表示具有开始和结束日期的民意调查。 在这两个日期之…

01数字基带信号及其频谱特性

S1 数字基带信号及其频谱特性 一、分类 1、单极性不归零波形 优点&#xff1a;电脉冲之间无间隔&#xff0c;极性单一&#xff0c;易于用TTL&#xff0c;CMOS电路产生&#xff1b; 缺点&#xff1a; a) 有直流成份&#xff1b;判决电平不能稳定在最佳的电平&#xff0c;抗噪声…

【渝粤教育】电大中专电商运营实操 作业 题库

1.电子商务最重要的是&#xff08; &#xff09; A.商务 B.网站 C.货物 D.信息技术 正确 正确答案&#xff1a;左边查询 学生答案&#xff1a;A 2.目前菜鸟网络依赖大数据和云计算已实现了哪些功能&#xff08; &#xff09; A.自动化仓库 B.智能发货 C.物流云加速 D.以上都正确…

人工智能英语学习笔记

基础篇单词 mythology n. ancient myths in general; ideas that many people think are true but that do not exist or are false 神话 Examples: A satyr is half man and half goat in Greek and Roman mythology. 在希腊和罗马神话中&#xff0c;森林之神是半人半羊的样子…