---
# System prepended metadata

title: Testing External Services

---

# Testing External Services
## 伺服器測試的四大主角

1. 客戶端(client)
2. 伺服器(server)
3. 假伺服器(fake server)
4. 調配器(adapter)

![](https://i.imgur.com/DiJBbcY.png)

1. Smoke test是從客戶端到實際伺服器進行完整測試
1. Integration test主要測試內部程式碼
2. Client unit test完全切割外部API連結，專注測試內部程式
3. Adapter unit test則是驗證adapter stub的結果是否與service相同


## Introducing VCR
- 在第一次發出請求後，會將結果存為YAML檔案
- 模擬的是貼近真實狀態下的反應
- 可以定期錄製（更新）YAML檔

## Client Unit Tests
```ruby=
describe  "avatars" do
  let(:user) {create(:user)}
> let(:fake_adapter) { instance_double(AvatarAdapter) }

  it "can get a twitter avatar URL" do
    allow(AcatarAdapter).to receive(:new).with(user).and_return(fake_adapter)
    allow(fake_adapter).to receive(:image_url).with(user).and_return("fake_url")
    expect(user.avatar_url).to eq("fake_url")
    expect(fake_adapter).to have_received(:image_url)
    expect(AcatarAdapter).to have_received(:new)
  end
end
```

### Why an Adapter?
- 如果程式中有多處地方需要發送請求到伺服器時
- 當發送請求時需要多筆數據與外部伺服器交流時

## Adapter Tests
```ruby=
require "rails_helper"

describe AvatarAdapter do
  it "accurately receives image url", :vcr do
    user = instance_double(User, twitter_handle: "noelrap")
    adapter = AvatarAdapter.new(user)
    url = "http://..."
    expect(adapter.image_url).to eq(url)
  end
end
```

## Testing for Error Cases
1. 直接將錯誤結果預錄下來，在每次測試時執行相關文件
2. 使用adapter test將特定方法（client端）stub後，預期回傳特定錯誤訊息
3. 使用adapter test將特定方法（client端）stub後，回傳非預期訊息

## Smoke Tests and VCR Options
```ruby=
VCR.use_cassette(re_record_interval: 7.days) #定期發出請求到外部伺服器
---------------------------------------------------------------------

VCR.configure do |c|
  c.default_cassette_options = { record: #options }
end

options
:all -> 持續與外部連結並更新
:new_episodes -> 更新已經發送過請求的
:none -> 只會使用錄製好的YAML檔，絕不會發送請求
:once -> 使用錄製好的YAML檔，若有新的請求，會發送後錄製
---------------------------------------------------------------------
:match_requests_on -> 只針對特定參數進行比對
```