Rails, Cypress : 测试整个堆栈肯定更容易

87 阅读6分钟

0.起源:Rails doctrine™

BootrAils,Cypress已经被集成、配置,并有一些测试来覆盖和记录应用程序。我们发现这个工具非常有趣,因为它与Rails哲学的一个精确点相匹配。

有价值的集成系统

这意味着,尽管是一个MVC框架,但视图、控制器和模型之间的边界更少,界限更模糊。这可能对任何Rails的新手来说都是一种伤害。

在一天结束的时候,即使各层没有完全分开,你也会有更高的生产力。

问题:鉴于单元测试要求在隔离的情况下进行测试,当各层没有完全隔离时,你如何测试任何东西?

幸运的是,有些测试实际上是在一起测试各层。

  • 集成测试
  • 系统测试
  • 端到端测试

所有这些类型的测试都是从外部检查行为。

1.从上到下测试Rails应用程序:不那么容易

在Cypress之前,用Rails测试整个堆栈并不是那么令人满意。我们所说的 "整个堆栈 "是指通过用户界面测试整个运行中的服务器、数据库、控制器等,就像一个普通用户会做的那样。你不得不把多个驱动程序、gem和lib粘在一起,最后你得到的是一个不太稳定的测试屏幕套件。Selenium用户知道在这个领域实现伟大的工作是多么复杂。

不幸的是,"最简单的Rails + RSpec + Capybara测试 "仍然不是特别简单

-Jason Swett,使用RSpec和Capybara的 "hello world"。

2.进入Cypress

Cypress有一个特点,就是不关心底层的测试屏幕。如果你在前端使用jQuery、Hotwire、AlpineJS或React,这都不重要。

Cypress在开发者中带来了很多积极性,在BootrAils我们特别喜欢它。其他人也是如此。

我们在工作中从Capybara转到了Cypress,我将永远不会再回去了。

-在Reddit上发现的。

这并不是说Capybara已经死了,而是Cypress的体验更好。

-也是在Reddit上发现的。

Cypress取代了对Capybara的需求。

3.Cypress和Rails,一场不可思议的婚礼

现在有一个非常好的消息:将Cypress集成到Rails中是非常简单的,因为已经有一个宝石可以实现

4.教程,从头开始

让我们安装一个新的Rails应用程序,并测试这个美丽的宝石。

首先,我们要检查我们的安全带。

$> ruby -v  
ruby 3.0.0p0 // you need at least version 3 here  
$> bundle -v  
Bundler version 2.2.11  
$> npm -v  
8.3.0 // you need at least version 7.1 here  
$> yarn -v  
1.22.10  
$> psql --version  
psql (PostgreSQL) 13.1 // let's use a production-ready database locally  

然后,我们创建一个裸露的Rails应用程序。

mkdir rails-with-cypress && cd rails-with-cypress  
echo "source 'https://rubygems.org'" > Gemfile  
echo "gem 'rails', '7.0.0'" >> Gemfile  
bundle install  
bundle exec rails new . --force --css=bootstrap -d=postgresql  
bundle update  
  
# Create a default controller  
echo "class HomeController < ApplicationController" > app/controllers/home_controller.rb  
echo "end" >> app/controllers/home_controller.rb  
  
# Create another controller (the one that should not be reached without proper authentication)  
echo "class OtherController < ApplicationController" > app/controllers/other_controller.rb  
echo "end" >> app/controllers/other_controller.rb  
  
# Create routes  
echo "Rails.application.routes.draw do" > config/routes.rb  
echo ' get "home/index"' >> config/routes.rb  
echo ' get "other/index"' >> config/routes.rb  
echo ' root to: "home#index"' >> config/routes.rb  
echo 'end' >> config/routes.rb  
  
# Create a default view  
mkdir app/views/home  
echo '<h1>This is home</h1>' > app/views/home/index.html.erb  
echo '<div><%= link_to "go to other page", other_index_path %></div>' >> app/views/home/index.html.erb  
  
# Create another view (will be also protected by authentication)  
mkdir app/views/other  
echo '<h1>This is another page</h1>' > app/views/other/index.html.erb  
echo '<div><%= link_to "go to home page", root_path %></div>' >> app/views/other/index.html.erb  
  
  
# Create database and schema.rb  
bin/rails db:create  
bin/rails db:migrate  
  

很好!快速检查一切是否正常运行,至少在本地是这样的,启动.NET。

./bin/dev  

并打开http://localhost:3000

从一个页面导航到另一个页面。这是我们应用程序的主要功能(哇!)。我们不希望每次在生产中推送新功能时都要手动测试它,所以让我们正确地自动测试它。

5.为Rails安装Cypress gem

首先,你将需要Cypress本身。运行:

yarn add --dev cypress  

将此添加到你的Gemfile中。

group :development, :test do  
  gem "cypress-rails"  
end  

然后运行。

bundle install  
# verbose logs...  
# ...  
# ...  
Using rails 7.0.0  
Fetching cypress-rails 0.5.3  
Using turbo-rails 7.1.1  
Installing cypress-rails 0.5.3  
Bundle complete! 18 Gemfile dependencies, 69 gems now installed.  
Use `bundle info [gemname]` to see where a bundled gem is installed.  

很好!Cypress已经安装完毕。

现在运行。

  bin/rails cypress:init  

好的!只有cypress.json文件被创建。

{  
  "screenshotsFolder": "tmp/cypress_screenshots",  
  "videosFolder": "tmp/cypress_videos",  
  "trashAssetsBeforeRuns": false  
}  

以上是cypress-rails的默认选项,你可以在这里找到所有可用的选项。

6.创建文件

正如你可能已经注意到的,到目前为止,你既没有测试也没有目录结构。Cypress足够聪明,在你第一次运行它时就提供了所需的一切。运行

bin/rails cypress:open  

等待几秒钟,然后Cypress的IDE应该出现,像这样。

cypress 1st launch

赛普拉斯第一次启动

Cypress建议你保留或删除现有的测试。我们建议你保留它们,它们作为一种参考是非常有用的

一旦保留,将它们剪切/粘贴到其他地方(在你的工作区的另一个地方),这样它们就不会在本教程中产生太大的噪音(一般来说,在你自己的项目中也是如此)。

这是创建的目录结构,位于你的Rails项目的根部。

root  
+-- cypress  
  +--fixtures  
  +--example.json  
  +--integration  
  +--plugins  
  +--index.js  
  +--support  
  +--commands.js  
  +--index.js  

integration 文件夹是你实际编写测试的地方:所有以*.spec.js 结尾的文件将在 Cypress IDE 中运行。

fixtures 文件夹是你为你的测试定义通用参考数据的地方,supportplugins 文件夹允许你扩展 Cypress 的功能。

7.我们自己的测试

正如你可能已经注意到的,集成文件夹不是空的。把所有的内容复制/粘贴到其他地方--里面的例子真的很有用,所以保留它们作为以后的参考。然后完全清空integration 文件夹中的内容。

然后写下以下测试。

// inside cypress/integration/home.spec.js
describe('Testing Home page', () => {  
  
  beforeEach(() => {  
    cy.visit('/')  
  })  
  
  it('Display a title by default', () => {  
    cy.get('h1').should('contain', 'This is home')  
  })  
  
  it('Allows to navigate from home page, to another', () => {  
    cy.get('a[href*="other/index"]').click()  
    cy.location().should((location) => {  
      expect(location.pathname).to.eq('/other/index')  
    })  
  })  
  
})  
  

然后在你的终端运行:

bin/rails cypress:open  

并在IDE中点击home.spec.js

cypress demo

cypress demo

很好!Cypress提供了一个很好的IDE,提供了很好的调试选项。

回到你的终端,停止Cypress(Ctrl+C)并运行

bin/rails cypress:run  

在其他冗长的日志中,你应该看到 。

Testing Home page  
✓ Display a title by default (542ms)  
✓ Allows to navigate from home page, to another (210ms)  
2 passing (776ms)  

很好!我们的Cypress套件可以在CI上运行,实际上没有必要为每个场景提供一个IDE。

8.一句话提醒

在BootrAils,我们发现它对两种情况极为有用。

  • 你的应用程序的 "幸福之路":你不希望你的应用程序的主要功能在每次发布时都出现问题。最健康的测试方式是当所有东西从A到Z都粘在一起时。
  • 在角落里,JavaScript和Rails控制器需要紧密合作。只有通过这种测试,才能正确地进行测试。

然而,不要试图用Cypress来达到每个用例。通过这种测试,上下文更难达到;此外,这些测试比基于Ruby的普通单元测试要慢。

除了这些警告之外,我们发现端到端测试终于是一股清风了,这要感谢Cypress。