rspec 测试页面元素

by Dmitriy Lutsko

德米特里·卢茨科(Dmitriy Lutsko)

如何使用RSpec对Go应用进行黑盒测试 (How to black box test a Go app with RSpec)

Automated testing is all the rage in web development these days and goes on across the whole industry. A well-written test dramatically reduces the risk of accidentally breaking an application when you add new features or fix bugs. When you have a complex system that’s built from several components that interact with each other, it’s incredibly hard to test how each component interacts with other components.

如今,自动化测试在Web开发中风靡一时,并在整个行业中不断发展。 精心编写的测试可以大大降低添加新功能或修复错误时意外破坏应用程序的风险。 当您有一个由多个相互交互的组件构建的复杂系统时,很难测试每个组件如何与其他组件交互。

Let’s take a look at how to write good automatic tests for developing components in Go and how to do so using the RSpec library in Ruby on Rails.

让我们看一下如何编写好的自动测试以在Go中开发组件,以及如何使用Ruby on Rails中的RSpec库来实现。

将Go添加到我们项目的技术堆栈中 (Adding Go to our project’s tech stack)

One of the projects that I’m working on at my company, eTeam, can be divided into an admin panel, user dashboard, report generator and request processor that handles requests from different services integrated into the application.

我在公司从事的项目之一eTeam可以分为管理面板,用户仪表板,报告生成器和请求处理器,它们可以处理来自集成到应用程序中的不同服务的请求。

The part of the project that processes requests is the most important, thus we needed to maximize its reliability and availability.

项目中处理请求的部分最为重要,因此我们需要最大限度地提高其可靠性和可用性。

As part of a monolithic application, there’s a high risk of a bug affecting the request processor, even when there are changes in code in parts of the app not related to it. Likewise, there’s a risk of crashing the request processor when other components are under a heavy load. The number of Ngnix workers for the app is limited, which can cause problems as the load increases. For instance, when a number of resource-intensive pages are opened at once in the admin panel, the processor slows down or even crashes the entire app.

作为整体应用程序的一部分,即使应用程序中与它不相关的部分中的代码发生更改,也存在错误影响请求处理器的高风险。 同样,当其他组件承受重负载时,也有可能使请求处理器崩溃。 该应用程序的Ngnix worker数量是有限的,随着负载的增加,这可能会引起问题。 例如,当在管理面板中一次打开大量资源密集的页面时,处理器会减慢速度甚至崩溃整个应用程序。

These risks, as well as the maturity of the system in question — we didn’t have to make major changes for months — made this app an ideal candidate for creating a separate service to handle request processing.

这些风险以及相关系统的成熟度(我们几个月都不必进行重大更改)使该应用程序成为创建单独服务来处理请求处理的理想选择。

We decided to write the separate service in Go, that shared the database access with the Rails application that remained responsible for changes in the table structure. With only two applications, such a scheme with a shared database works fine. Here’s what it looked like:

我们决定用Go编写单独的服务,该服务与仍负责表结构更改的Rails应用程序共享数据库访问权限。 仅使用两个应用程序,这种具有共享数据库的方案就可以正常工作。 看起来是这样的:

We wrote and deployed the service in a separate Rails instance. This way, there was no need to worry that the request processor would be affected whenever the Rails app was deployed. The service directly accepts HTTP requests without Ngnix and doesn’t use a lot of memory. You could call it a minimalist app!

我们在单独的Rails实例中编写和部署了该服务。 这样,无需担心部署Rails应用程序时请求处理器会受到影响。 该服务无需Ngnix即可直接接受HTTP请求,并且不占用大量内存。 您可以将其称为简约应用!

Go中的单元测试问题 (The problem with unit testing in Go)

We created unit tests for the Go application where all database requests were mocked. In addition to other arguments for this solution, the main Rails application was responsible for the database structure, thus the Go application didn’t actually have the information for creating a test database. Half of processing was business logic, while the other half was database queries, all of which were mocked.

我们为模拟所有数据库请求的Go应用程序创建了单元测试。 除了该解决方案的其他参数之外,主要的Rails应用程序还负责数据库结构,因此Go应用程序实际上没有创建测试数据库的信息。 处理的一半是业务逻辑,而另一半是数据库查询,所有这些都是模拟的。

Mocked objects are much less readable in Go than in Ruby. Whenever new functions were added for reading data from the database, we had to add mocked objects during many failed tests that had previously worked. In the end, such unit tests didn’t prove very effective and were extremely fragile.

在Go中,模拟对象比在Ruby中可读性低得多。 每当添加新功能以从数据库读取数据时,我们就不得不在许多以前无法通过的失败测试中添加模拟对象。 最后,这种单元测试并没有证明非常有效,而且非常脆弱。

我们的解决方案 (Our solution)

In order to make up for these drawbacks, we decided to cover the service with functional tests in the Rails application and test the service in Go like a black box. White-box testing wouldn’t work in any case, since it was impossible to use Ruby to get inside the service and see whether a method was being called.

为了弥补这些缺陷,我们决定在Rails应用程序中对服务进行功能测试,并像黑盒子一样在Go中测试服务。 白盒测试在任何情况下都不起作用,因为不可能使用Ruby进入服务内部并查看是否正在调用方法。

That also means that requests sent through the test service were also impossible to mock, thus we needed another application for managing and writing these tests. Something like RequestBin would work, but it had to work locally. We’d already written a utility that’d do the trick, so we decided to try using it.

这也意味着通过测试服务发送的请求也无法被模拟,因此我们需要另一个应用程序来管理和编写这些测试。 像RequestBin这样的东西可以工作,但必须在本地工作。 我们已经编写了可以解决问题的实用程序,因此我们决定尝试使用它。

This was the resulting setup:

这是结果设置:

  1. RSpec compiles and runs the Go binary with the configuration in which access to the test database is specified along with a particular port for receiving HTTP requests, i.e 8082.RSpec使用以下配置编译并运行Go二进制文件:在该配置中,指定了对测试数据库的访问以及用于接收HTTP请求的特定端口,即8082。
  2. It also runs the utility, which records HTTP requests coming to port 8083.它还运行该实用程序,该实用程序记录到端口8083的HTTP请求。
  3. We write regular tests in RSpec. This creates the necessary data in the database and sends a request to localhost:8082 as if it were an external service such as HTTParty.我们在RSpec中编写常规测试。 这将在数​​据库中创建必要的数据,并将请求发送到localhost:8082,就好像它是外部服务(例如HTTParty)一样。
  4. We parse the response, check changes in the database, receive a list of requests that were recorded by the RequestBin substitute and check them.我们解析响应,检查数据库中的更改,接收由RequestBin替代项记录的请求列表并进行检查。

实施细节 (Details of the implementation)

Here’s how we implemented this. As a demonstration, let’s call the test service TheService and create a wrapper:

这是我们实现此方法的方式。 作为演示,我们将测试服务称为TheService并创建一个包装器:

It’s worth mentioning that autoloading files have to be configured in the support folder when using RSpec:

值得一提的是,使用RSpec时,必须在support文件夹中配置自动加载文件:

Dir[Rails.root.join('spec/support/**/*.rb')].each {|f| require f}

The start method:

启动方法:

  • Reads the configuration information necessary to start TheService. This information can differ among different developers and therefore is excluded from Git. The configuration contains the necessary settings for starting the program. All of these different configurations are in a single place so you don’t have to create unnecessary files.读取启动TheService所需的配置信息。 这些信息在不同的开发人员中可能有所不同,因此从Git中排除。 该配置包含用于启动程序的必要设置。 所有这些不同的配置都放在一个地方,因此您不必创建不必要的文件。
  • Compiles and runs through go run <path to main.go> <path to config>

    编译并通过go run <path to main.go> <path t config的go run <path to main.go> <path t >运行

  • Polls every second and waits until TheService is ready to accept requests.每秒轮询一次,直到TheService准备好接受请求为止。
  • Records the identifier of each process in order to not repeat anything and to have the ability to stop a process.记录每个进程的标识符,以便不重复任何内容并具有停止进程的能力。

The configuration itself:

配置本身:

The “stop” method simply stops the process. There’s a gotcha though! Ruby runs a “go run” command, which compiles TheService and launches a binary in a child process with an unknown ID. If we just stop the process that’s running in Ruby, the child process doesn’t stop automatically and the port will remain in use. Thus stopping TheService has to go through the Process Group ID:

“停止”方法只是停止该过程。 虽然有陷阱! Ruby运行“ go run”命令,该命令编译TheService并在子进程中以未知ID启动二进制文件。 如果我们只是停止在Ruby中运行的进程,则子进程不会自动停止,并且该端口将继续使用。 因此,停止TheService必须经过Process Group ID:

Next we prepare the “shared_context” where we define the default variables, start TheService if it hasn’t already been launched and temporarily turn off VCR since VCR would see what we’re doing as an external service request, but we don’t want VCR to mock requests at this point:

接下来,我们准备“ shared_context”,在其中定义默认变量,如果尚未启动,则启动TheService,并暂时关闭VCR,因为VCR会看到我们在做外部服务请求,但我们不想VCR此时模拟请求:

And now we can look at writing the specs themselves:

现在我们可以看看自己编写规范:

TheService can make HTTP requests to external services. We can configure it to redirect requests to the local utility that logs them. For this utility, there’s also a wrapper for starting and stopping it that’s similar to ‘TheServiceControl’, except that this utility can just be started as a binary without compilation.

TheService可以向外部服务发出HTTP请求。 我们可以配置它以将请求重定向到记录请求的本地实用程序。 对于此实用程序,还有一个用于启动和停止它的包装程序,类似于“ TheServiceControl”,不同之处在于,该实用程序可以作为二进制文件启动而无需编译。

其他亮点 (Additional highlights)

The Go application was written so that all the logs and debugging information would be sent to STDOUT. On production, this output is sent to a file. When launching from RSpec the log is displayed in the console, which really helps with debugging.

编写Go应用程序是为了将所有日志和调试信息发送到STDOUT。 在生产中,此输出将发送到文件。 从RSpec启动时,日志将显示在控制台中,这确实有助于调试。

If you specifically run the specs that don’t need TheService, then it won’t start.

如果您专门运行不需要TheService的规范,则它将不会启动。

In order not to waste time on launching TheService each time whenever a spec changes, during the development process you can launch TheService manually in the terminal and simply not turn it off. Whenever it’s necessary, you can even launch it in an IDE debugging mode. Then the specs prepare everything, send the request to the service, it stops and you can easily debug it. This makes the TDD approach really convenient.

为了避免每次更改规范时都浪费时间启动TheService,在开发过程中,您可以在终端中手动启动TheService,而不必关闭它。 必要时,您甚至可以在IDE调试模式下启动它。 然后,规范准备了一切,将请求发送到服务,它停止了,您可以轻松调试它。 这使得TDD方法非常方便。

结论 (Conclusion)

We’ve been using this setup for about a year now and haven’t experienced any failures with it. The specs come out far more readable than unit testing in Go, and they don’t rely on knowing the internal structure of the service. If we, for some reason, need to rewrite the service in another language, then we won’t need to change the specs. Only the wrappers, which are used for launching the test service with a different command would need to be rewritten.

我们已经使用此设置大约一年了,并且没有遇到任何失败。 规范的发布远比Go中的单元测试更具可读性,并且它们不依赖于了解服务的内部结构。 如果由于某种原因我们需要用另一种语言重写服务,那么我们就不需要更改规格。 只有用于使用其他命令启动测试服务的包装程序才需要重写。

翻译自: https://www.freecodecamp.org/news/how-to-black-box-test-a-go-app-with-rspec-421e786f4103/

rspec 测试页面元素

rspec 测试页面元素_如何使用RSpec对Go应用进行黑盒测试相关推荐

  1. rspec 测试页面元素_如何使用共享示例使您的RSpec测试干燥

    rspec 测试页面元素 by Parth Modi 由Parth Modi 如何使用共享示例使您的RSpec测试干燥 (How to DRY out your RSpec Tests using S ...

  2. (转)selenium页面元素定位八大方法_琉璃

    2019独角兽企业重金招聘Python工程师标准>>> 转自:https://www.cnblogs.com/qingchunjun/p/4208159.html 在使用seleni ...

  3. eclipse在网页进入时显示重定向过多_使用eclipse快速开发jsp以及编码问题、jsp页面元素、request对象学习的粗略记录...

    人老了真是什么都会忘记啊orz,早上发现学过去的东西好多都还没记录复盘... ...(懒虫作祟) 在开始之前,俺认为还是很有必要了解一下jsp的执行流程,俺发现CSDN上的"陈小哥cw&qu ...

  4. angular跳转指定页面_通过 angular CDK 实现页面元素拖放

    通过导入@angular/cdk/drag-drop模块我们可以轻松实现元素在页面中得拖放功能,如元素在页面中随意拖动.在特定区域内拖动亦或对列表进行拖放排序等等. 通过 angular CDK 实现 ...

  5. Appium 自动化测试 H5页面元素定位

    简介   在现在的移动端App中,由于开发效率.需求频繁变更的需求情况下,经常有相关的运营需求,经常要进行更新,如果全部采用原生开发,需要的成本比较高,后来就出现了内嵌的H5页面.那么这些H5页面元素 ...

  6. 使用Selenium含蓄等待获取页面元素(附带实际业务需求情景)

    Hello,大家好,又到了小猿分享技术的时间了.这回带来的是使用Selenium去网站上获取部分信息并且执行部分操作以及"含蓄"等待元素加载完成以及截取图片和网页刷新机制的技术点. ...

  7. 拾壹博客拆解,页面元素替换(二)

    页面元素替换 首先要做的当然是换成自己风格的站名和内容啦. 1.网站配置 跟踪前端代码后发现配置是来自后端接口,想着既然入库了,那应该有对应的管理页面吧,果然找到了,就是-演示账号不允许操作!那么接下 ...

  8. 使用页面元素属性做状态判断的隐患

    在做DHTML开发的时候,依赖一些页面元素的得值来作为页面的状态的判断,初看似乎并没有什么问题.可是在后期的开发和维护中,却是一个随时可能产生莫名其妙bug的隐藏炸弹.如果不小心引爆,那就只有郁闷的份 ...

  9. Python selenium根据class定位页面元素,xpath定位

    Python selenium根据class定位页面元素 在日常的网页源码中,我们基于元素的id去定位是最万无一失的,id在单个页面中是不会重复的.但是实际工作中,很多前端开发人员并未给每个元素都编写 ...

最新文章

  1. 量子CNN不存在梯度消失问题,物理学家已完成理论证明
  2. seaborn可视化水平箱图并添加抖动数据点(Horizontal boxplot with jittered points in Python)
  3. Dicom Test Files
  4. 介绍 WebLogic 的一些结构和特点
  5. 小程序入门学习20--springboot之集成mybatis
  6. python批量下载bilibili视频_如何批量下载bilibili的视频?
  7. 文本居中对齐(CSS、HTML)
  8. mysql提高运行效率_提升Mysql执行效率的SQL优化技巧汇总
  9. 190317每日一句
  10. 声网(agora)音视频通话sdk—微信小程序demo
  11. 聚焦“生态化”,e签宝讲好电子签名的“中国故事”
  12. 在学习时,遇到in module ssbuild. File is included in 4 contexts
  13. 《代码整洁之道》笔记整理
  14. 微信小程序获得二维码
  15. 计算机fn的作用,fn是什么键 笔记本电脑fn键作用大全
  16. 算法技能树2-蓝桥杯-python实现测试次数(摔手机)-动态规划(DP)
  17. 照片编辑后怎么恢复到之前
  18. Java练习、每日一题、共100题
  19. Swift 5.0 (二) 可选类型 、函数
  20. 有没有测试女生暗恋的软件,教你一个小技巧就可以测试女生是否喜欢你!

热门文章

  1. 【设计模式】设计模式C++编程实现之策略模式(Strategy Pattern)
  2. jquery-尺寸相关
  3. 算法--生成1~n的排列
  4. usermod使用方法
  5. Python + Selenium + Chrome 使用代理 auth 的用户名密码授权
  6. [Cracking the Coding Interview] 4.1 Route Between Nodes 节点间的路径
  7. express 4.*升级后带来的影响
  8. 优化反射性能的总结(上)
  9. 修改数据库的兼容级别
  10. 9th, Jan 2012 养成好的生活习惯真的很不容易