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

rspec 测试页面元素

by Parth Modi

由Parth Modi

如何使用共享示例使您的RSpec测试干燥 (How to DRY out your RSpec Tests using Shared Examples)

Give me six hours to chop down a tree and I will spend the first four sharpening the axe.” — Abraham Lincoln

给我六个小时的时间来砍树,我将用头四个时间来削斧头。” - 亚伯拉罕·林肯

When I refactored a project a few weeks ago, I spent most of my time writing specs. After writing several similar test cases for some APIs, I started to wonder whether I might be able to get rid of a lot of this duplication.

几周前重构项目时,我大部分时间都在编写规范。 在为某些API编写了几个类似的测试用例之后,我开始怀疑我是否可以摆脱很多重复。

So I threw myself into reading up on the best practices for DRYing up tests (Don’t Repeat Yourself). And that’s how I came to know of shared examples and shared contexts.

因此,我开始阅读有关烘干测试的最佳做法(不要重复自己)。 这就是我了解shared examplesshared contexts

In my case, I ended up using shared examples. And here’s what I’ve learned so far from applying these.

就我而言,我最终使用了共享示例。 到目前为止,这是我从应用这些知识中学到的。

When you have multiple specs that describe similar behavior, it might be better to extract redundant examples into shared examples and use them in multiple specs.

当您有多个描述相似行为的规范时,将冗余示例提取到shared examples并在多个规范中使用它们可能会更好。

Suppose you have two models User and Post, and a user can have many posts. Users should be able to view list of users and posts. Creating an index action in the users and posts controllers will serve this purpose.

假设您有两个模型UserPost ,一个用户可以有多个帖子。 用户应该能够查看用户列表和帖子。 在用户和发布控制器中创建索引操作将达到此目的。

First, write specs for your index action for the users controller. It will have the responsibility of fetching users and rendering them with proper layout. Then write enough code to make tests pass.

首先,为用户控制器编写索引操作的规范。 它将负责获取用户并以正确的布局呈现用户。 然后编写足够的代码以使测试通过。

# users_controller_spec.rbdescribe "GET #index" do  before do     5.times do      FactoryGirl.create(:user)     end    get :index  end  it {  expect(subject).to respond_with(:ok) }  it {  expect(subject).to render_template(:index) }  it {  expect(assigns(:users)).to match(User.all) }end
# users_controller.rbclass UsersController < ApplicationController  ....  def index    @users = User.all  end  ....end

Typically, the index action of any controller fetches and aggregates data from few resources as required. It also adds pagination, searching, sorting, filtering and scoping.

通常,任何控制器的索引操作都根据需要从很少的资源中获取并聚合数据。 它还增加了分页,搜索,排序,过滤和作用域。

Finally, all these data are presented to views via HTML, JSON, or XML using APIs. To simplify my example, the index actions of controllers will just fetch data, then show them via views.

最后,所有这些数据都使用API​​通过HTML,JSON或XML呈现给视图。 为了简化我的示例,控制器的索引动作将仅获取数据,然后通过视图显示它们。

The same goes for the index action in the posts controller:

posts控制器中的index操作也是如此:

describe "GET #index" do   before do     5.times do      FactoryGirl.create(:post)    end    get :index  end  it {  expect(subject).to respond_with(:ok) }  it {  expect(subject).to render_template(:index) }  it {  expect(assigns(:posts)).to match(Post.all) }end
# posts_controller.rbclass PostsController < ApplicationController  ....  def index    @posts = Post.all  end  ....end

RSpec tests written for both users and posts controller are very similar. In both controllers we have:

为用户和帖子控制器编写的RSpec测试非常相似。 在两个控制器中,我们都有:

  • The response code — should be ‘OK’

    响应码-应该为“ OK”
  • Both index action should render proper partial or view — in our case index

    两种索引操作都应呈现适当的局部或视图-在我们的案例中是index

  • The data we want to render, such as posts or users

    我们要呈现的数据,例如帖子或用户

Let’s DRY the specs for our index action by using shared examples.

让我们通过使用shared examples来干燥索引操作的规范。

共享示例放在哪里 (Where to put your shared examples)

I like to place shared examples inside the specs/support/shared_examples directory so that all shared example-related files are loaded automatically.

我喜欢将共享示例放置在specs / support / shared_examples目录中,以便自动shared example所有shared example相关的文件。

You can read about other commonly used conventions for locating your shared examples here: shared examples documentation

您可以在此处了解其他用于查找shared examples常用约定: 共享示例文档

如何定义一个共享的例子 (How to define a shared example)

Your index action should respond with 200 success code (OK) and render your index template.

您的索引操作应以200成功代码(OK)响应,并呈现您的索引模板。

RSpec.shared_examples "index examples" do   it { expect(subject).to respond_with(:ok) }  it { expect(subject).to render_template(:index) }end

Apart from your it blocks — and before and after your hooks — you can add let blocks, context, and describe blocks, which can also be defined inside shared examples.

除了您的it块(在钩子之前和之后)之外,您还可以添加let块,上下文和描述块,它们也可以在shared examples定义。

I personally prefer to keep shared examples simple and concise, and don’t add contexts and let blocks. The shared examples block also accepts parameters, which I’ll cover below.

我个人更喜欢使共享示例简单明了,不要添加上下文和让块。 shared examples块还接受参数,我将在下面介绍。

如何使用共享示例 (How to use shared examples)

Adding include_examples "index examples" to your users and posts controller specs includes “index examples” to your tests.

向您的用户添加include_examples "index examples" ,并发布控制器规范,其中包括对测试的“索引示例”。

# users_controller_spec.rbdescribe "GET #index" do  before do     5.times do      FactoryGirl.create(:user)     end    get :index  end  include_examples "index examples"  it {  expect(assigns(:users)).to match(User.all) }end
# similarly, in posts_controller_spec.rbdescribe "GET #index" do  before do     5.times do      FactoryGirl.create(:post)     end    get :index  end  include_examples "index examples"  it {  expect(assigns(:posts)).to match(Post.all) }end

You can also use it_behaves_like or it_should_behaves_like instead of include_examples in this case. it_behaves_like and it_should_behaves_like are actually aliases, and work in same manner, so they can be used interchangeably. But include_examples and it_behaves_like are different.

在这种情况下,您也可以使用it_behaves_likeit_should_behaves_like代替include_examplesit_behaves_likeit_should_behaves_like实际上是别名,并且以相同的方式工作,因此可以互换使用。 但是include_examplesit_behaves_like是不同的。

As stated in the official documentation:

如官方文档中所述:

  • include_examples — includes examples in the current context

    include_examples在当前上下文中包含示例

  • it_behaves_like and it_should_behave_like include the examples in a nested context

    it_behaves_likeit_should_behave_like将示例包含在嵌套上下文中

为什么这种区别很重要? (Why does this distinction matter?)

RSpec’s documentation gives a proper answer:

RSpec的文档给出了正确的答案:

When you include parameterized examples in the current context multiple times, you may override previous method definitions and last declaration wins.

当您在当前上下文中多次包含参数化示例时,您可以覆盖以前的方法定义,最后声明会获胜。

So when you face situation where parameterized examples contain methods that conflict with other methods in same context, you can replace include_examples with it_behaves_like method. This will create a nested context and avoid this kind of situations.

因此,当遇到参数化示例包含与同一上下文中其他方法冲突的方法的情况时,可以使用it_behaves_like方法替换include_examples 。 这将创建一个嵌套的上下文并避免这种情况。

Check out the following line in your users controller specs, and posts controller specs:

在用户控制器规范中查看以下行,并发布控制器规范:

it { expect(assigns(:users)).to match(User.all) }it { expect(assigns(:posts)).to match(Post.all) }

Now your controller specs can be re-factored further by passing parameters to shared example as below:

现在,可以通过将参数传递给共享示例来进一步重构控制器规格,如下所示:

# specs/support/shared_examples/index_examples.rb
# here assigned_resource and resource class are parameters passed to index examples block RSpec.shared_examples "index examples" do |assigned_resource, resource_class|   it { expect(subject).to respond_with(:ok) }  it { expect(subject).to render_template(:index) }  it {  expect(assigns(assigned_resource)).to match(resource_class.all)   }end

Now, make following changes to your users and posts controller specs:

现在,对您的用户进行以下更改并发布控制器规格:

# users_controller_spec.rbdescribe "GET #index" do  before do     ...  end  include_examples "index examples", :users, User.allend
# posts_controller_spec.rbdescribe "GET #index" do  before do     ...  end  include_examples "index examples", :posts, Post.allend

Now controller specs look clean, less redundant and more importantly, DRY. Furthermore, these index examples can serve as basic structures for designing the index action of other controllers.

现在,控制器规格看起来很整洁,减少了冗余,更重要的是DRY。 此外,这些索引示例可以用作设计其他控制器的索引动作的基本结构。

结论 (Conclusion)

By moving common examples into a separate file, you can eliminate duplication and improve the consistency of your controller actions throughout your application. This is very useful in case of designing APIs, as you can use the existing structure of RSpec tests to design tests and create APIs that adhere to your common response structure.

通过将常见示例移到单独的文件中,您可以消除重复并提高整个应用程序中控制器操作的一致性。 这在设计API时非常有用,因为您可以使用RSpec测试的现有结构来设计测试并创建符合您的通用响应结构的API。

Mostly, when I work with APIs, I use shared examples to provide me with a common structure to design similar APIs.

通常,当我使用API​​时,我会使用shared examples为我提供一个通用的结构来设计相似的API。

Feel free to share how you DRY up your specs by using shared examples.

通过使用shared examples随时分享您如何干燥规格。

翻译自: https://www.freecodecamp.org/news/how-to-dry-out-your-rspec-tests-using-shared-examples-d5cc5d33fd76/

rspec 测试页面元素

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值