markdown RSPEC

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了markdown RSPEC相关的知识,希望对你有一定的参考价值。

### Uses
* Useful for testing logic in your app (models and controller)
* Not views, as RSPEC does not come with a web driver 
* **TDD** = Test Driven Development
* Tests ensure to a high level that your code functions the way you intended it to
* Saves time figuring out where in your code there could be bugs

### Initial Setup
* Create an app: `rails new app_name -T`
    * The `-T` option lets you skip the Test Unit (testing framework that comes with Rails)
* In Gemfile:

```ruby
group :development, :test do 
  gem 'rspec'
end
```

* Run `bundle install`
* In terminal: `rails generate rspec:install`
* In terminal: `rails g model dummy_model name:string`
* NOTICE the output in the terminal: `invoke rspec  create spec/models/dummy_model_spec.rb`
    * Rails has created the associated `_spec.rb` file
    * IN ALL `_spec.rb` files, at the top, include: `require 'rails_helper'`
    * That required file was generated by the `rspec:install`
* If you **manually** create your test files, make sure they are appended with `_spec`!
* In terminal: run the following commands: `rake db:migrate` & `rake db:test:prepare`
    * The first command will run the migration for the model and the second command sets up the
    **test** database with that model as well

### TESTING
* Once all is completed, the command to run the entire test suite is `rake`
    * Alternatively, you can also run the entire test suite by using `bundle exec rspec` or just
    `rspec`
    * Only a subset of tests: `bundle exec rspec spec/models`
* To run only a single test file: `bundle exec rspec spec/models/dummy_model_spec.rb`


### SYNTAX
* **describe**
    * `describe`
    * Used to organize your specs
    * You can reference your classes or just strings
    * 
    ```ruby
    describe User do
    
    end
    
    describe 'Some string' do
    
    end
    ```
* **TIP**: tighten your scope further by providing a method name (instance
or class):

```ruby
describe User, "#get_name" do         # instance method

end

describe Movie, ".upcoming" do        # class method

end
```

* **it**
    * the testing code will be inserted into this block
    * it's main use is to document the behavior of what you expect the function to accomplish
    
    ```ruby
    describe Agent, "#favorite_gadget" do
      it "returns one item, the fav gadget of the agent" do 
        #...
      end

    end
    ```
    
* **expect()**
    * let's you verify or falsify the part of the system you want to test
    * it expects an object and a method to be called on the object and is used
    in conjuction with `.to eq` or `.not_to eq`
    
    ```ruby
    describe Agent, "#favorite_gadget" do
      it "returns one item, the fav gadget of the agent" do 
        expect(agent.favorite_gadget).to eq "Hammer"
        # previously, should() is used
      end

    end
    ```
    
---

### Format

```ruby
describe User, "get_name" do

  it 'retrieves the user\'s name' do
   # SETUP
   user = User.create(name: "Bob")
   
   # EXERCISE
   name = user.get_name
   
   # VERIFY
   expect(name).to eq 'Bobby'
   
   # TEARDOWN
   # down automatically by RSPEC
   
  end

end
```

---

### Matchers
* methods like `.to eq`
* `.to be_truthy` or `.to be true`
    * `expect(object.method_name?).to be_truthy` || `expect(object.method_name?).to be true`
    * `to be_truthy` will pass if the value returned is NOT `nil` or `false`!!
    * `to be true` will only pass if the returned value is `true`!
* `.to be_falsy` or `to be false`
    * `to be_falsy` expects the return value to be `false` or `nil`
    * `to be false` only expects `false`
* `to be_nil` or `to_not be_nil`
* `.to_match()`: argument is a regex expression, to better generalize a value 
    * `expect(value).to match(/\d{3}/)`
* You can use `<`, `>`, `<=`, `>=` for better coverage:
    * `expect(value).to be < 4`
* **TEST for CLASSES**:
    * `to be_an_instance_of`
    * `.to be_a`
    * `.to be_an`
    
    ```ruby
    expect(value).to be_an_instance_of(User)
    expect(value).to be_a(ActiveRecord::Associations::CollectionProxy)
    ```
* **ERROR HANDLING**
    * `.to raise_error`
    * `.to raise_error(ErrorClass)`
    * `.to raise_error(ErrorClass, 'Some error message')`
    * `.to raise_error('Some error') ` - no error class mentioned, just the message
    * ErrorClass: NoMethodError, NameError, ...
* Collections
    * `.to start_with`: does the collection start with this value
    * `.to end_with`: does the collection end with this value
    * `.to include`: check the contents of the collection
* RSPEC gives you the ability to create your own matchers(the functions described above) if in
your model, you have a method that is defined using a question mark, it is converted in your rpsec
test `to be_name_of_method`

---

### Let
* `let` and `let!` are helper methods that evaluates when the spec uses it or loads the value
beforehand (`let!`)

```ruby
describe Mission, "#prepare", :let do
  let(:mission) { Mission.create(name: "Moonraker") }
  let!(:bond) {Agent.create(name: 'James Bond') }

  it 'adds agents to a mission' do
    mission.prepare(bond)
    expect(mission.agents).to include bond
  end
end
```

* **NOTE**: `let!` is used to evaluate before the spec uses it, this can slow down your tests
because it will evaluate before each question!

---

### Callbacks
* `before(:each)`: runs before each test example

```ruby
describe Agent, '#favorite_gadget' do
  before(:each) do
    @gadget = Gadget.create(name: "Laser Pen") # MAKE SURE THIS IS AN INSTANCE VARIABLE!!!
  end

  it 'blah blah' do
    # can use @gadget variable
  end
end
```

* `before(:all)`: runs code in the block before all the other examples in a spec file
* `after(:each)` and `after(:all)`, are run AFTER your tests have been executed!

---
### Generators 
* `rails g rspec:install`: (ran initially in the above code)
* Need another dummy model spec?: `rails g rspec:model name_of_model`
    * The output of this: `create spec/models/name_of_model_spec.rb`
* Need a spec for controller testing? `rspec controller`
    * `rails g rspec:controller name_of_controller`
    * Output: `spec/controllers/name_of_controller_spec.rb`
* There is a spec for views as well: `rspec:views`, much better alternative `Capybara`
* **`rspec helper`**
    * `rails g rspec:helper name_of_helper`
    * creates `spec/helpers/name_of_helper_helper_spec.rb`
    * `_helper_spec.rb` is automatically prepended!
    * `spec/support` is the place to write helper methods that come up during refactoring
    * `spec/helpers` is the place to write code for your **view helpers**
    * Need to run your helper methods on a helper object!
    
    ```ruby
    # helper spec file
    describe '#set_date' do
      helper.set_date
    end
    ```

---
### Tags
* You can add a tag in your `describe` block that allows you to run test certain code that are
organize in a group

```ruby
describe Agent, :wip do
  # code
end
```

* In terminal: `rspec --tag wip`
* To **exclude** these tests: `rspec --tag ~wip`
* To run multiple tagged tests: `rspec --tag wip checkout`

以上是关于markdown RSPEC的主要内容,如果未能解决你的问题,请参考以下文章

markdown RSPEC

markdown Rspec - TDD

markdown RSpec备忘单

markdown js:trueにしたRSpecのE2Eテストがjavascriptが実行できずに失败する

我无法使用 'bundle exec rspec' 执行 rspec

是否有RSpec等效的RSpec来做TDD?