ASTRO Camp 11th
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Owners
        • Signed-in users
        • Everyone
        Owners Signed-in users Everyone
      • Write
        • Owners
        • Signed-in users
        • Everyone
        Owners Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights New
    • Engagement control
    • Make a copy
    • Transfer ownership
    • Delete this note
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Note Insights Versions and GitHub Sync Sharing URL Help
Menu
Options
Engagement control Make a copy Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Owners
  • Owners
  • Signed-in users
  • Everyone
Owners Signed-in users Everyone
Write
Owners
  • Owners
  • Signed-in users
  • Everyone
Owners Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       Owned this note    Owned this note      
    Published Linked with GitHub
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    # 20220822 RSPEC ###### tags: `Ruby` `Rails` `Duck typing` ## 測試 > hello 尼好嗎 > HIHI~ 晚上好啊~ > 偷偷聊天 抓! ```shell= $ rails _6.1.6_ new <name> $ bundle add rspec-rails $ rails g rspec:install $ rails g model Product title description:text price:integer $ rails g rspec:model Cart #可以產生出Cart的model的測試檔 ``` ![](https://i.imgur.com/lE1tYny.png) 會提示你一些東西的奇妙指令 ```shell! $ rails g ``` ![](https://i.imgur.com/1YsoDtR.png =200x) 這只是一部份! 如果出現這個: ![](https://i.imgur.com/gEvRMsB.png) /Gemfile ![](https://i.imgur.com/YcHwuyr.png) 可以去參考柚子的部落格喔! https://hackmd.io/@yoji/HJDIzuQRq ## 小設定(非必要) 把 ```ruby= config.default_formatter = "doc" ``` 加到 spec_helper.rb 的 RSpec.configure 的 block 裡,每次執行 rspec 後得到的測試訊息會變成這樣: ```ruby CartItem 每個 Cart Item 都可以計算它自己的金額(小計)。 Cart 可以把商品丟到到購物車裡,然後購物車裡就有東西了。 如果加了相同種類的商品到購物車裡,購買項目(CartItem)並不會增加,但商品的數量會改變。 (略) Finished in 0.02977 seconds (files took 0.84509 seconds to load) 8 examples, 0 failures ``` ## 購物車測試 [龍哥原始教材](https://railsbook.tw/chapters/27-shopping-cart-part-1) 購物車存取紀錄: - cookie 容量較小 通常擺認證 - localstorage > https://pragprog.com/titles/rails6/agile-web-development-with-rails-6/ ```shell rails g rspec:install ``` 對於購物車的期望: * 可以把商品丟到到購物車裡,然後購物車裡就有東西了。 * 如果加了相同種類的商品到購物車裡,購買項目(CartItem)並不會增加,但商品的數量會改變。 * 商品可以放到購物車裡,也可以再拿出來。 * 每個 Cart Item 都可以計算它自己的金額(小計)。 * 可以計算整台購物車的總消費金額。 * 特別活動可搭配折扣(例如聖誕節的時候全面打 9 折,或是滿額滿千送百或滿額免運費)。 ### 測試開始 ```ruby! require 'rails_helper' Cart = 1 RSpec.describe Cart, type: :model do it "works" do expect(1).to be 1 end end ``` 這樣寫是強迫讓他測試成功,但不會這樣寫。 也不會用`rails g model Cart`,因為沒有要存進資料庫。 所以可以去 app/model 手動自己新增檔案 ![](https://i.imgur.com/QnGtDU0.png) 這樣測試也會過: ![](https://i.imgur.com/PJmfHGE.png) ### duck typing > 為什麼 ruby 要寫測試 > 沒有型別檢查,所以要測 ```ruby #duck typing def aaa(x) x.abc end ``` 我不在意你的型別(整數或陣列),只要能支援abc方法就好了。 這樣會把`x`稱為`鴨子型別(duck typing)` 這時候x沒有abc方法就爆炸了,問題會在運行時才會發現。 雖然這樣的寫法是方便的,但是相對來說是鬆散的。 如果有錯,上線後才會被發現,這時候就已經來不及了。 所以寫測試的目的是因為沒辦法保證寫的東西一定是對的,因為沒有型別的檢查。 所以寫測試在 Ruby 圈是很重要的。 TypeScripts 是javascript的superset Java ### initialize ![](https://i.imgur.com/YK9qkUI.png) 執行 add ,都會產生一個新陣列,這樣他的商品永遠就只會有一樣 所以可以用`initialize` ```ruby! def initialize @items = [] end ``` new 之後才會執行,所以可以不用加到 add 裡去做。 ```ruby list = [1,2,3,4,5] target = 6 p list.find{ |a| a == target } ``` ![](https://i.imgur.com/4iFBhhU.png) 因為沒有做判斷,所以才會有8個 但是以目前陣列的資料結構無法滿足條件。 所以可以用hash。 雖然可以直接用hash,但之後還會有其他功能。 所以另外再開新的資料夾 ![](https://i.imgur.com/KNfRZnC.png) ![](https://i.imgur.com/WUkazgZ.png) ### 這邊超複雜的~ **`initialize(product_id, quantity = 1)`** 增加彈性 ```ruby! #/cart.rb def add(product_id, quantity = 1 ) found_item = @items.find{ |item| item.product_id == product_id} if found_item @items += 1 found_item.increment(quantity) else @items << CartItem.new(product_id, quantity) end end #/cart_item.rb class CartItem attr_reader :product_id, :quantity def initialize(product_id, quantity = 1) @product_id = product_id @quantity = quantity end end ``` 如果沒有講數量,可以藉由參數的預設值去 +1 不指定 quantity > 初始值 為 1 有指定 quantity > 可一次增加 > 1 的數量 ```ruby= cart.add(apple) # +1 apple cart.add(banana, 2) # +2 banana ``` ### 第三項 ```ruby! cart.items.fitst <-- 裡面是CartItme ``` ruby 裡充滿了省略過後的產物: ```ruby! # before expect(cart.items.count).to(be(2)) # after expect(cart.items.count).to be 2 ``` #### 一心二用?! **一個 `it` 裡面盡量只有 一個 `expect`** 頂多兩個 這邊只想知道拿出來的是否為商品 ``` ruby! expect(cart.items.first.product).to be_a Product ``` 但也可以更精準 ``` ruby! expect(cart.items.first.product.price).to be 10 ``` ### factory bot > 快速產生資料 `$ bundle add factory_bot_rails` ![](https://i.imgur.com/9rok7kx.png) ```ruby! p1 = FactoryBot.create(:product) ``` 這邊這樣寫直接壞給你看 ![](https://i.imgur.com/Ckc5tK5.png) 還記得我們價錢是寫多少嗎? 是 **10** 所以當然會壞,可以這樣寫: ```ruby! p1 = FactoryBot.create(:product, price: 10) ``` **在業界也是在用工廠來生產資料,這個一定要學會** 可以省略**FactoryBot** 在/spec/rails_helper.rb放這個 ```ruby! RSpec.configure do |config| config.include FactoryBot::Syntax::Methods end ``` ```ruby! p1 = create(:product, price: 10) ``` ```ruby! @items.reduce(0) {|acc, cv| acc + cv } # 0 是初始值 ``` class Product end PORO = Plain Old Ruby Object 沒有繼承的class ### 時間套件(測試用 控制時間,停在某時期) [timecop](https://github.com/travisjeffery/timecop) ```$bundle add timecop``` Time.now.year 現在的時間 ```ruby! Timecop.travel(t) expect(cart.total_price).to be 117 # 測完記得跳回正常的時間 Timecop.return ``` ### 滿千送百 ![](https://i.imgur.com/hzagYMm.png) 現判斷是否為聖誕節, 如果是就也有滿千送百; 如不是聖誕節, 就只有滿千送百。 這邊的順序要注意不能顛倒,不然結果會不一樣。 ### 進階功能 因為購物車將會以 Session 方式儲存,所以: 1. 可以將購物車內容轉換成 Hash 並存到 Session 裡。 2. 也可以存放在 Session 的內容(Hash 格式),還原成購物車的內容。 為甚麼要先把購物車內容換成 Hash ? > 這是因為沒有經過這樣的轉換,存進去的就會是一段記憶體位址,或是可以說是物件,當你換頁的時候,這段就會消失。 > ![](https://i.imgur.com/agx48ar.png =400x) #### be vs eq ```shell! 1 be 1 O 1 eq 1 O "1" be "1" X "1" eq "1" O ``` be 會去比較是否為同一物件 eq 指得是`==` 更詳細的介紹: https://medium.com/lynns-dev-blog/rails-%E6%96%B0%E6%89%8B%E6%9D%91-rspec-%E4%B8%AD-eq-eql-be-%E7%9A%84%E5%B7%AE%E5%88%A5-226192f8f59e ## 序列化 serialize 剛剛 hash 轉Session這個過程叫做序列化。 [維基百科-序列化](https://zh.wikipedia.org/zh-tw/序列化) ## rubocop 檢查ruby語法套件 https://github.com/rubocop/rubocop ![](https://i.imgur.com/4277tsv.png =300x)

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully