为Openshift + MongoDb应用程序编写验收测试

验收测试用于确定是否满足规范要求。 它应该在与生产环境尽可能相似的环境中运行。 因此,如果您的应用程序已部署到Openshift中,则您将需要一个与生产环境中使用的帐户平行的帐户,以运行测试。 在这篇文章中,我们将为部署到Openshift的应用程序编写验收测试,该应用程序使用MongoDb作为数据库后端。

部署的应用程序是一个非常非常简单的库,它返回所有可借出的书。 该应用程序使用MongoDb来存储与书籍有关的所有信息。

因此,让我们开始描述先前应用程序的目标,功能,用户故事和接受标准。

目标 :扩大对大多数人的授课范围。
功能 :显示可用的书。
用户故事 :浏览目录->为了查找我想借的书,作为用户,我希望能够浏览所有书。 验收标准 :应该查看所有可用的书。

场景:

鉴于我想借一本书
当我在目录页面时
然后,我应该会看到可用的书籍信息:罐子之王– 1299 – LOTRCoverUrl,霍比特人– 293 – HobbitCoverUrl

注意,这是一个非常简单的应用程序,因此接受标准也很简单。

对于此示例,我们需要两个测试框架,第一个用于编写和运行验收测试,另一个用于管理NoSQL后端。 在这篇文章中,我们将使用修昔底德ATDDNoSQLUnit对付MongoDB的

该应用程序已经部署在Openshift中 ,您可以查看https://books-lordofthejars.rhcloud.com/GetAllBooks

Thucydides是一种工具,旨在简化编写自动验收和回归测试的过程。

Thucydides使用WebDriver API访问HTML页面元素。 而且还可以帮助您通过使用具体的编程模型来组织测试和用户故事,创建已执行测试的报告,最后还可以测量功能覆盖率。

要用Thucydides编写验收测试,应遵循以下步骤。

  • 首先,选择您的功能之一的用户故事。
  • 然后实现PageObject类。 PageObject是一种将Web应用程序的用户界面元素建模为对象的模式,因此测试可以以编程方式与其交互。 请注意,在这种情况下,我们正在编码“如何”访问HTML页面。
  • 下一步是实现步骤库。 此类将包含执行操作所需的所有步骤。 例如,创建新书需要打开addnewbook页面,插入新数据,然后单击提交按钮。 在这种情况下,我们正在编码“什么”来实现验收标准。
  • 最后,按照定义的验收标准并使用先前的步骤类对选定的用户故事进行编码。

NoSQLUnit是一个JUnit扩展,旨在使我们能够管理所需的NoSQL引擎的生命周期,帮助我们将数据库维护为已知状态并简化为NoSQL应用程序编写测试的方式。

NoSQLUnit由两组JUnit规则和两个注释组成。 在当前情况下,我们不需要管理NoSQL引擎的生命周期,因为它是由外部实体( Openshift )管理的。

因此,让我们开始工作:

我们要做的第一件事是创建一个不包含测试代码的要素类。 它用作表示需求结构的一种方式。

public class Application {@Featurepublic class Books {public class ListAllBooks {}}}

请注意,每个实现的功能都应包含在带有@Feature注释的类中。 特色类的每种方法都代表一个用户故事。

下一步是创建PageObject类。 请记住,PageObject模式将Web应用程序的用户界面建模为对象。 因此,让我们看一下html文件,以检查必须映射的元素。

<table id='listBooks' cellspacing='0' cellpadding='5'><caption>List of Available Books<caption><tr><th>Title<th><th>Number Of Pages<th><th>Cover<th><tr>.....<table>

这里最重要的是标记具有一个名为listBooksID ,将在PageObject类中使用该ID以获得对其参数和数据的引用。 让我们编写页面对象:

@DefaultUrl('http:books-lordofthejars.rhcloud.comGetAllBooks')public class FindAllBooksPage extends PageObject {@FindBy(id = 'listBooks')private WebElement tableBooks;public FindAllBooksPage(WebDriver driver) {super(driver);}public TableWebElement getBooksTable() {Map<String, List<String>> tableValues = new HashMap<String, List<String>>();tableValues.put('titles', titles());tableValues.put('numberOfPages', numberOfPages());tableValues.put('covers', coversUrl());return new TableWebElement(tableValues);}private List<String> titles() {List<WebElement> namesWebElement = tableBooks.findElements(By.className('title'));return with(namesWebElement).convert(toStringValue());}private List<String> numberOfPages() {List<WebElement> numberOfPagesWebElement = tableBooks.findElements(By.className('numberOfPages'));return with(numberOfPagesWebElement).convert(toStringValue());}private List<String> coversUrl() {List<WebElement> coverUrlWebElement = tableBooks.findElements(By.className('cover'));return with(coverUrlWebElement).convert(toImageUrl());}private Converter<WebElement, String> toImageUrl() {return new Converter<WebElement, String>() {@Overridepublic String convert(WebElement from) {WebElement imgTag = from.findElement(By.tagName('img'));return imgTag.getAttribute('src');}};}private Converter<WebElement, String> toStringValue() {return new Converter<WebElement, String>() {@Overridepublic String convert(WebElement from) {return from.getText();}};}}

使用@DefaultUrl我们设置要映射的URL,使用@FindBy我们映射ID为listBooks的Web元素,最后映射返回生成的html表内容的getBooksTable()方法。

接下来要做的是实现步骤类。 在这种简单的情况下,我们只需要两步,第一步打开GetAllBooks页面,另一步断言该表包含期望的元素。

public class EndUserSteps extends ScenarioSteps {public EndUserSteps(Pages pages) {super(pages);}private static final long serialVersionUID = 1L;@Steppublic void should_obtain_all_inserted_books() {TableWebElement booksTable = onFindAllBooksPage().getBooksTable();List<String> titles = booksTable.getColumn('titles');assertThat(titles, hasItems('The Lord Of The Rings', 'The Hobbit'));List<String> numberOfPages = booksTable.getColumn('numberOfPages');assertThat(numberOfPages, hasItems('1299', '293'));List<String> covers = booksTable.getColumn('covers');assertThat(covers, hasItems('http:upload.wikimedia.orgwikipediaen662Jrrt_lotr_cover_design.jpg', 'http:upload.wikimedia.orgwikipediaen44aTheHobbit_FirstEdition.jpg'));}@Steppublic void open_find_all_page() {onFindAllBooksPage().open();}private FindAllBooksPage onFindAllBooksPage() {return getPages().currentPageAt(FindAllBooksPage.class);}}

最后是验证验收标准的课程:

@Story(Application.Books.ListAllBooks.class)@RunWith(ThucydidesRunner.class)public class FindBooksStory {private final MongoDbConfiguration mongoDbConfiguration = mongoDb().host('127.0.0.1').databaseName('books').username(MongoDbConstants.USERNAME).password(MongoDbConstants.PASSWORD).build();@Rulepublic final MongoDbRule mongoDbRule = newMongoDbRule().configure(mongoDbConfiguration).build();@Managed(uniqueSession = true)public WebDriver webdriver;@ManagedPages(defaultUrl = 'http:books-lordofthejars.rhcloud.com')public Pages pages;@Stepspublic EndUserSteps endUserSteps;@Test@UsingDataSet(locations = 'books.json', loadStrategy = LoadStrategyEnum.CLEAN_INSERT)public void finding_all_books_should_return_all_available_books() {endUserSteps.open_find_all_page();endUserSteps.should_obtain_all_inserted_books();}}

在上一堂课中应该考虑一些事项:

  • @Story应该收到一个使用@Feature批注定义的类,以便Thucydides可以正确创建报告。
  • 我们使用MongoDbRule建立与远程MongoDb实例的连接。 请注意,由于端口转发具有Openshift功能,因此我们可以使用本地主机地址,因此尽管使用了本地主机,但实际上我们正在管理远程MongoDb实例。
  • 使用@Steps Thucydides将创建先前步骤库的实例。
  • 最后使用@UsingDataSet批注在运行测试之前将数据填充到MongoDb数据库中。
{'book':[{'title': 'The Lord Of The Rings','numberOfPages': '1299','cover': 'http:upload.wikimedia.orgwikipediaen662Jrrt_lotr_cover_design.jpg' }, {'title': 'The Hobbit','numberOfPages': '293','cover': 'http:upload.wikimedia.orgwikipediaen44aTheHobbit_FirstEdition.jpg'}]}

请注意, NoSQLUnit通过在每次测试执行之前清理数据库并将其定义为json文件中的已知数据来填充数据库, 从而将数据库保持为已知状态。

还请记住,此示例非常简单,因此仅显示了ThucydidesNoSQLUnit功能的一小部分。 继续观看两个网站: http : //thucydides.info和https://github.com/lordofthejars/nosql-unit

我们不断学习,
亚历克斯

参考:来自我们的JCG合作伙伴 Alex Soto的Openshift + MongoDb应用程序的编写验收测试,位于One Jar To Rule All All博客上。

翻译自: https://www.javacodegeeks.com/2012/12/writing-acceptance-tests-for-openshift-mongodb-applications.html

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

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

相关文章

CSS 自适应布局

前言 本篇文章将介页面布局中的自适应布局&#xff0c;常见的自适应布局有以下2种&#xff1a;左列固定右列自适应、左右两列固定中间自适应。 1. 左列固定右列自适应布局方案 说明&#xff1a;左列固定右列自适应&#xff0c;也可以为右列固定左列自适应&#xff0c;常见于中…

mysql的表导出er关系图_使用Navicat生成ER关系图并导出的方法

平时管理数据库一般都是用cmd命令提示符&#xff0c;或是IDEA Intellij自带的Data source&#xff0c;使用Navicat比较少。这段时间&#xff0c;由于要对前后端交互的数据结构进行设计&#xff0c;直接写文档联系多表时有些困难&#xff0c;想着如果有关系图就直观很多。想到Na…

Scude导入MySQL_FM2017_FMF赛季更新和真实修正数据库[更新至9.9,超过89000个更新]

FM2017_FMF赛季更新和真实修正数据库[更新至9.9&#xff0c;超过89000个更新]FM2017_FMF赛季更新和真实修正数据库[更新至9.9&#xff0c;超过89000个更新](2)这是国外玩家制作的一款FM2017_FMF冬季更新和真实修正数据库&#xff0c;更新至9月9日&#xff0c;超过89000个更新内…

音视频和表单的详情

网页中的音视频 <audio> 和 <vedio> 标签属性&#xff1a;autoplay 自动播放 controls 控制播放 loop 循环播放 表单 HTML 表单用于收集用户输入。 标签<form> 标签属性 action 数据的路径 enctype 传输文件 enctype"multipart/form-data" method …

mysql otter 数据同步_MySQL数据同步之otter

一、otter介绍基于日志数据&#xff0c;用于MySQL或者ORACLE之间准实时同步数据。用途&#xff1a;mysql/oracle互相同步中间表/行记录同步二、原理及架构图otter整体模块manager (提供web页面进行同步管理)arbitrate (分布式调度&#xff0c;可跨IDC机房)node (同步过程setl)c…

ubuntu中获取文件名称并生成txt文件

简介&#xff1a; 在机器视觉学习过程中&#xff0c;通常会经常批量处理一些图片&#xff0c;在&#xff35;&#xff42;&#xff55;&#xff4e;&#xff54;&#xff55;下可以使用find命令&#xff0c;来实现将文件名全部读取出来&#xff0c;生成列表txt文件&#xff0c;…

HTMLCSS

HTML xml &#xff08;标签名&#xff09;可扩展标记语言 <Stu> </Stu> Html 超文本标记语言&#xff08;文本&#xff0c;图片&#xff0c;链接&#xff09; <> </> Internet网上编写页面&#xff08;H5版本&#xff1a;支持多种标签特性&…

java中i+=2什么意思_三分钟看懂Java中i++与++i的性能差别以及循环中如何使用

在Java中&#xff0c;自增是一种非常常见的操作&#xff0c;在自增中&#xff0c;有两种写法&#xff0c;一种是前缀自增(i)&#xff0c;一种是后缀自增(i)。这里主要简单介绍两种自增的差别。一、含义差别前缀自增和后缀自增是不同的。前缀自增(i)是从内存中加载i&#xff0c;…

动态规划:从新手到专家

作者&#xff1a;Hawstein出处&#xff1a;http://hawstein.com/posts/dp-novice-to-advanced.html前言 本文翻译自TopCoder上的一篇文章&#xff1a; Dynamic Programming: From novice to advanced &#xff0c;并非严格逐字逐句翻译&#xff0c;其中加入了自己的一些理解。水…

小程序 foreach_【第2106期】小程序依赖分析实践

前言这种可视化分析图还是很直观的&#xff0c;很有趣。今日早读文章由自然醒授权分享。正文从这开始~~用过 webpack 的同学肯定知道 webpack-bundle-analyzer &#xff0c;可以用来分析当前项目 js 文件的依赖关系。webpack-bundle-analyzer因为最近一直在做小程序业务&#x…

python----模块

collections---------------------------------------->扩展数据类型 re-------------------------------------------------->正则相关操作&#xff0c;正则 匹配字符串 time----------------------------------------------->时间相关 三种格式&#xff1a;时间戳&…

css渲染(二) 文本

一、文本样式 首行缩进  text-indent 首行缩进是将段落的第一行缩进&#xff0c;这是常用的文本格式化效果。一般地&#xff0c;中文写作时开头空两格。[注意]该属性可以为负值&#xff1b;应用于: 块级元素(包括block和inline-block)  <div><p style"text-in…

28岁学python转行_28岁转行程序员,学Java还是Python?码农:想快点月薪过万就选它...

为什么要学Java&#xff1f;Python给人的印象简单是因为我们在用Python的时候&#xff0c;可以直接调用别人已经写好的代码接口就可以&#xff0c;相对于傻瓜模式&#xff0c;Java的许多处理都要原生很多&#xff0c;写的代码可能会多一些&#xff0c;但一旦完成封装&#xff0…

CSS布局(五) 网页布局方式

网页实质是块与块之间的位置&#xff0c;块挨着块&#xff0c;块嵌套块&#xff0c;块叠着块。 三种关系&#xff1a;相邻&#xff0c;嵌套&#xff0c;重叠。 下面介绍网页布局的常用几种方式 1.一列布局&#xff1a; 一般都是固定的宽高&#xff0c;设置margin : 0 auto来水…

变量声明declare,简单运算符运算,变量测试与内容替换

declare -/ 选项 变量名 - 设类型 取消类型 -i 设为整型 -x 设为环境变量 -p 显示类型属性&#xff08;property&#xff09; [rootlocalhost ~]# a1 [rootlocalhost ~]# declare -p a declare -- a"1" [rootlocalhost ~]# export a [rootlocalhost ~]# declare -p …

如何水平居中一个元素

在项目中经常会遇到居中问题&#xff0c;这里借鉴度娘的众多答案&#xff0c;做一个总结&#xff1a; 一、元素的水平居中 1、行级元素的水平居中 <div style"width: 200px;height: 100px;border: 1px solid cyan; text-align: center;"><span>行级元素…

Yammer Metrics,一种监视应用程序的新方法

当您运行诸如Web应用程序之类的长期应用程序时&#xff0c;最好了解一些关于它们的统计信息&#xff0c;例如&#xff0c;服务的请求数&#xff0c;请求持续时间或活动请求数。 但是还有一些更通用的信息&#xff0c;例如内部集合的状态&#xff0c;代码的某些部分被执行了多少…

mysql教程目录_MySql目录(二)

MySql索引(二) 转自&#xff1a; http://www.cnblogs.com/dreamhome/archive/2013/04/16/3025304.html 所有MySQL列类型可以被索引。根据存储引擎定义每个表的最大索引数和最大索引长度。 所有存储引擎支持每个表至少16个索引&#xff0c;总索引长度至少为256字节。大多数存储引…

solr和Lucene的配置方式和应用

solr字段类型 类说明BinaryField二进制数据BoolField布尔值&#xff0c;其中’t’/’T’/’1’都是trueCollationFiled支持Unicode排序CurrencyField支持货币和汇率DateRangeFiled支持索引date rangeExternamFiledFiledpull磁盘上的文件EnumField支持定义枚举值ICUCollationFie…

CSS——清除浮动的六种解决方案

内容的高度撑起父元素容器的高度&#xff0c;效果图如下HTML和CSS代码如下给&#xff50;标签加上浮动以后&#xff0c;&#xff50;&#xff5b;float&#xff1a;left&#xff1b;&#xff5d;&#xff0c;此时DIV塌陷&#xff0c;两段内容同行显示&#xff0c;效果如下&…