ne_api 0.0.20 → 0.0.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +157 -0
- data/config/api.yaml +6 -0
- data/lib/ne_api/testing/fake_auth.rb +109 -0
- data/lib/ne_api/testing/fake_master.rb +177 -0
- data/lib/ne_api/testing/response_factory.rb +227 -0
- data/lib/ne_api/testing/rspec_helpers.rb +154 -0
- data/lib/ne_api/testing.rb +44 -0
- data/lib/ne_api/version.rb +1 -1
- metadata +8 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7c0274cd24bfbca15098ae69851b86bab0fd70bef4df5b802c42208525ddfb01
|
|
4
|
+
data.tar.gz: f1456cf436fd67297e14e30d3fd869279d69582ff77fd6b131f2d4acfd253f5c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c56d55baa11ef1e6b321d6de18e76cebb971837c74da56fde6f49d2292620c1a7d4dcbef49a7a8c1c9b8ee30cbc719a610ee66ac8b0dcb6c41222ff59950d5f1
|
|
7
|
+
data.tar.gz: 578330d042baf2e7de275f37bd07480be2368ef361828c7e1c8369bc0b8c71ef5da694f2bdc552cb1da3f0a32c14dbfda6b06d5f5122d474e6575478bf317faf
|
data/README.md
CHANGED
|
@@ -103,6 +103,160 @@ end
|
|
|
103
103
|
|
|
104
104
|
```
|
|
105
105
|
|
|
106
|
+
## Testing Support (RSpec)
|
|
107
|
+
|
|
108
|
+
ne_api provides built-in stub classes for testing in Rails applications.
|
|
109
|
+
|
|
110
|
+
### Setup
|
|
111
|
+
|
|
112
|
+
Add to your `spec/rails_helper.rb`:
|
|
113
|
+
|
|
114
|
+
```ruby
|
|
115
|
+
require 'ne_api/testing'
|
|
116
|
+
|
|
117
|
+
RSpec.configure do |config|
|
|
118
|
+
config.include NeAPI::Testing::RSpecHelpers
|
|
119
|
+
end
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Basic Usage
|
|
123
|
+
|
|
124
|
+
#### Using `with_fake_ne_api` block
|
|
125
|
+
|
|
126
|
+
```ruby
|
|
127
|
+
RSpec.describe OrderSyncService do
|
|
128
|
+
it "syncs orders from Next Engine" do
|
|
129
|
+
with_fake_ne_api do |fake|
|
|
130
|
+
# Stub API responses
|
|
131
|
+
fake.stub(:receiveorder_base_search, [
|
|
132
|
+
ne_receive_order(receive_order_id: "ORDER001", receive_order_total_amount: 5000),
|
|
133
|
+
ne_receive_order(receive_order_id: "ORDER002", receive_order_total_amount: 3000)
|
|
134
|
+
])
|
|
135
|
+
|
|
136
|
+
service = OrderSyncService.new
|
|
137
|
+
result = service.sync
|
|
138
|
+
|
|
139
|
+
expect(result.count).to eq 2
|
|
140
|
+
expect(fake.called?(:receiveorder_base_search)).to be true
|
|
141
|
+
expect(fake.call_count(:receiveorder_base_search)).to eq 1
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
#### Direct injection (recommended for services with DI)
|
|
148
|
+
|
|
149
|
+
```ruby
|
|
150
|
+
RSpec.describe StockService do
|
|
151
|
+
let(:fake_master) { fake_ne_master }
|
|
152
|
+
|
|
153
|
+
before do
|
|
154
|
+
fake_master.stub(:master_stock_search, [
|
|
155
|
+
ne_stock(stock_goods_id: "GOODS001", stock_quantity: 100)
|
|
156
|
+
])
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
it "fetches stock data" do
|
|
160
|
+
service = StockService.new(ne_api: fake_master)
|
|
161
|
+
stocks = service.fetch_all
|
|
162
|
+
|
|
163
|
+
expect(stocks.first["stock_quantity"]).to eq 100
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### Simulating Errors
|
|
169
|
+
|
|
170
|
+
```ruby
|
|
171
|
+
it "handles API errors" do
|
|
172
|
+
with_fake_ne_api do |fake|
|
|
173
|
+
fake.simulate_error(code: "001001", message: "Authentication failed")
|
|
174
|
+
|
|
175
|
+
expect { service.sync }.to raise_error(NeAPIException, /001001/)
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### Authentication Testing
|
|
181
|
+
|
|
182
|
+
```ruby
|
|
183
|
+
RSpec.describe AuthController do
|
|
184
|
+
it "authenticates user" do
|
|
185
|
+
with_fake_ne_auth do |fake_auth|
|
|
186
|
+
fake_auth.stub_auth_response({
|
|
187
|
+
"access_token" => "custom_access_token",
|
|
188
|
+
"refresh_token" => "custom_refresh_token",
|
|
189
|
+
"company_ne_id" => "NE999999"
|
|
190
|
+
})
|
|
191
|
+
|
|
192
|
+
post :callback, params: { uid: "test_uid", state: "test_state" }
|
|
193
|
+
|
|
194
|
+
expect(session[:access_token]).to eq "custom_access_token"
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
it "handles authentication failure" do
|
|
199
|
+
with_fake_ne_auth do |fake_auth|
|
|
200
|
+
fake_auth.stub_auth_failure
|
|
201
|
+
|
|
202
|
+
expect {
|
|
203
|
+
post :callback, params: { uid: "test_uid", state: "test_state" }
|
|
204
|
+
}.to raise_error(NeAPIException)
|
|
205
|
+
end
|
|
206
|
+
end
|
|
207
|
+
end
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### Available Factory Methods
|
|
211
|
+
|
|
212
|
+
| Method | Description |
|
|
213
|
+
|--------|-------------|
|
|
214
|
+
| `ne_goods(**attrs)` | Generate goods master data |
|
|
215
|
+
| `ne_goods_list(count)` | Generate list of goods |
|
|
216
|
+
| `ne_stock(**attrs)` | Generate stock data |
|
|
217
|
+
| `ne_stock_list(count)` | Generate list of stocks |
|
|
218
|
+
| `ne_receive_order(**attrs)` | Generate receive order data |
|
|
219
|
+
| `ne_receive_order_list(count)` | Generate list of orders |
|
|
220
|
+
| `ne_receive_order_row(**attrs)` | Generate order row data |
|
|
221
|
+
| `ne_shop(**attrs)` | Generate shop data |
|
|
222
|
+
| `ne_warehouse_stock(**attrs)` | Generate warehouse stock data |
|
|
223
|
+
| `ne_company_info(**attrs)` | Generate company info |
|
|
224
|
+
| `ne_user_info(**attrs)` | Generate user info |
|
|
225
|
+
| `ne_error(code:, message:)` | Generate error response |
|
|
226
|
+
|
|
227
|
+
### FakeMaster Methods
|
|
228
|
+
|
|
229
|
+
| Method | Description |
|
|
230
|
+
|--------|-------------|
|
|
231
|
+
| `stub(method_name, response)` | Stub a specific API method |
|
|
232
|
+
| `simulate_error(code:, message:)` | Enable error mode |
|
|
233
|
+
| `clear_error` | Disable error mode |
|
|
234
|
+
| `reset!` | Clear all stubs and history |
|
|
235
|
+
| `called?(method_name)` | Check if method was called |
|
|
236
|
+
| `call_count(method_name)` | Get call count |
|
|
237
|
+
| `last_call_args(method_name)` | Get last call arguments |
|
|
238
|
+
|
|
239
|
+
### Service Design for Testability
|
|
240
|
+
|
|
241
|
+
For best testability, design your services to accept `ne_api` as a dependency:
|
|
242
|
+
|
|
243
|
+
```ruby
|
|
244
|
+
class OrderSyncService
|
|
245
|
+
def initialize(ne_api: nil)
|
|
246
|
+
@ne_api = ne_api || NeAPI::Master.new(
|
|
247
|
+
access_token: Rails.application.credentials.ne_access_token,
|
|
248
|
+
refresh_token: Rails.application.credentials.ne_refresh_token
|
|
249
|
+
)
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
def sync
|
|
253
|
+
@ne_api.receiveorder_base_search
|
|
254
|
+
end
|
|
255
|
+
end
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
This allows easy injection of `FakeMaster` in tests.
|
|
259
|
+
|
|
106
260
|
## Contributing
|
|
107
261
|
|
|
108
262
|
1. Fork it ( https://github.com/[my-github-username]/ne_api/fork )
|
|
@@ -112,6 +266,9 @@ end
|
|
|
112
266
|
5. Create a new Pull Request
|
|
113
267
|
|
|
114
268
|
## Update
|
|
269
|
+
### ver0.0.21
|
|
270
|
+
* 倉庫別の在庫などに対応
|
|
271
|
+
* rspecも作成
|
|
115
272
|
### ver0.0.18
|
|
116
273
|
* 受注税金内訳取得APIに対応
|
|
117
274
|
### ver0.0.17
|
data/config/api.yaml
CHANGED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
module NeAPI
|
|
2
|
+
module Testing
|
|
3
|
+
# NeAPI::Auth のスタブクラス
|
|
4
|
+
#
|
|
5
|
+
# @example 基本的な使い方
|
|
6
|
+
# fake = NeAPI::Testing::FakeAuth.new(redirect_url: "http://localhost:3000/callback")
|
|
7
|
+
# fake.ne_auth("uid123", "state456")
|
|
8
|
+
# fake.tokens #=> { access_token: "...", refresh_token: "..." }
|
|
9
|
+
#
|
|
10
|
+
# @example カスタムレスポンス
|
|
11
|
+
# fake.stub_auth_response({ "access_token" => "custom_token", ... })
|
|
12
|
+
# fake.ne_auth("uid", "state")
|
|
13
|
+
#
|
|
14
|
+
# @example 認証失敗のシミュレート
|
|
15
|
+
# fake.stub_auth_failure
|
|
16
|
+
# fake.ne_auth("uid", "state") #=> raises NeAPIException
|
|
17
|
+
#
|
|
18
|
+
class FakeAuth
|
|
19
|
+
attr_accessor :redirect_url, :ne_user, :wait_flag
|
|
20
|
+
|
|
21
|
+
def initialize(redirect_url: "http://localhost:3000/callback")
|
|
22
|
+
@redirect_url = redirect_url
|
|
23
|
+
@ne_user = nil
|
|
24
|
+
@wait_flag = false
|
|
25
|
+
@auth_response = nil
|
|
26
|
+
@should_fail = false
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# 認証レスポンスをカスタマイズする
|
|
30
|
+
#
|
|
31
|
+
# @param response [Hash] 認証レスポンス
|
|
32
|
+
# @return [self]
|
|
33
|
+
def stub_auth_response(response)
|
|
34
|
+
@auth_response = response
|
|
35
|
+
self
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# 認証失敗をシミュレートする
|
|
39
|
+
#
|
|
40
|
+
# @return [self]
|
|
41
|
+
def stub_auth_failure
|
|
42
|
+
@should_fail = true
|
|
43
|
+
self
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# スタブをリセットする
|
|
47
|
+
#
|
|
48
|
+
# @return [self]
|
|
49
|
+
def reset!
|
|
50
|
+
@ne_user = nil
|
|
51
|
+
@auth_response = nil
|
|
52
|
+
@should_fail = false
|
|
53
|
+
self
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# ブラウザを開かずにサインインURLを返す
|
|
57
|
+
#
|
|
58
|
+
# @param client_id [String] クライアントID
|
|
59
|
+
# @param client_secret [String] クライアントシークレット
|
|
60
|
+
# @return [String] コールバックURLの例
|
|
61
|
+
def sign_in(client_id = nil, client_secret = nil)
|
|
62
|
+
# 実際のブラウザは開かない
|
|
63
|
+
# テスト用にコールバックURLを返す
|
|
64
|
+
"#{@redirect_url}?uid=test_uid&state=test_state"
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# 認証処理のスタブ
|
|
68
|
+
#
|
|
69
|
+
# @param uid [String] UID
|
|
70
|
+
# @param state [String] State
|
|
71
|
+
# @param client_id [String] クライアントID
|
|
72
|
+
# @param client_secret [String] クライアントシークレット
|
|
73
|
+
# @return [Hash] 認証レスポンス
|
|
74
|
+
# @raise [NeAPIException] 認証失敗時
|
|
75
|
+
def ne_auth(uid, state, client_id = nil, client_secret = nil)
|
|
76
|
+
raise NeAPIException, "003001:認証に失敗しました" if @should_fail
|
|
77
|
+
|
|
78
|
+
@ne_user = @auth_response || default_auth_response(uid)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# トークンを取得する
|
|
82
|
+
#
|
|
83
|
+
# @return [Hash, nil] トークン情報
|
|
84
|
+
def tokens
|
|
85
|
+
return nil if @ne_user.nil?
|
|
86
|
+
|
|
87
|
+
{
|
|
88
|
+
access_token: @ne_user["access_token"],
|
|
89
|
+
refresh_token: @ne_user["refresh_token"]
|
|
90
|
+
}
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
private
|
|
94
|
+
|
|
95
|
+
def default_auth_response(uid)
|
|
96
|
+
{
|
|
97
|
+
"result" => "success",
|
|
98
|
+
"uid" => uid,
|
|
99
|
+
"access_token" => "test_access_token_#{uid}",
|
|
100
|
+
"refresh_token" => "test_refresh_token_#{uid}",
|
|
101
|
+
"access_token_end_date" => (Time.now + 3600).strftime("%Y-%m-%d %H:%M:%S"),
|
|
102
|
+
"refresh_token_end_date" => (Time.now + 86400 * 30).strftime("%Y-%m-%d %H:%M:%S"),
|
|
103
|
+
"company_app_name" => "Test Company",
|
|
104
|
+
"company_ne_id" => "NE123456"
|
|
105
|
+
}
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
module NeAPI
|
|
2
|
+
module Testing
|
|
3
|
+
# NeAPI::Master のスタブクラス
|
|
4
|
+
#
|
|
5
|
+
# @example 基本的な使い方
|
|
6
|
+
# fake = NeAPI::Testing::FakeMaster.new
|
|
7
|
+
# fake.stub(:master_goods_search, [{ "goods_id" => "001" }])
|
|
8
|
+
# fake.master_goods_search #=> [{ "goods_id" => "001" }]
|
|
9
|
+
#
|
|
10
|
+
# @example エラーのシミュレート
|
|
11
|
+
# fake.simulate_error(code: "001001", message: "認証エラー")
|
|
12
|
+
# fake.master_goods_search #=> raises NeAPIException
|
|
13
|
+
#
|
|
14
|
+
class FakeMaster
|
|
15
|
+
attr_accessor :access_token, :refresh_token, :wait_flag, :retry_num, :wait_interval
|
|
16
|
+
attr_accessor :access_token_end_date, :refresh_token_end_date
|
|
17
|
+
attr_reader :call_history
|
|
18
|
+
|
|
19
|
+
def initialize(access_token: "test_access_token", refresh_token: "test_refresh_token")
|
|
20
|
+
@access_token = access_token
|
|
21
|
+
@refresh_token = refresh_token
|
|
22
|
+
@wait_flag = false
|
|
23
|
+
@retry_num = 10
|
|
24
|
+
@wait_interval = 15
|
|
25
|
+
@stubbed_responses = {}
|
|
26
|
+
@call_history = []
|
|
27
|
+
@error_mode = false
|
|
28
|
+
@error_code = nil
|
|
29
|
+
@error_message = nil
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# 特定メソッドのレスポンスをスタブする
|
|
33
|
+
#
|
|
34
|
+
# @param method_name [Symbol, String] スタブするメソッド名
|
|
35
|
+
# @param response [Object] 返却するレスポンス(ブロックも可)
|
|
36
|
+
# @return [self]
|
|
37
|
+
def stub(method_name, response = nil, &block)
|
|
38
|
+
@stubbed_responses[method_name.to_sym] = block || -> (_) { response }
|
|
39
|
+
self
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# エラーモードを有効にする
|
|
43
|
+
#
|
|
44
|
+
# @param code [String] エラーコード
|
|
45
|
+
# @param message [String] エラーメッセージ
|
|
46
|
+
# @return [self]
|
|
47
|
+
def simulate_error(code: "001001", message: "API Error")
|
|
48
|
+
@error_mode = true
|
|
49
|
+
@error_code = code
|
|
50
|
+
@error_message = message
|
|
51
|
+
self
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# エラーモードを解除する
|
|
55
|
+
#
|
|
56
|
+
# @return [self]
|
|
57
|
+
def clear_error
|
|
58
|
+
@error_mode = false
|
|
59
|
+
@error_code = nil
|
|
60
|
+
@error_message = nil
|
|
61
|
+
self
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# 全スタブと呼び出し履歴をクリアする
|
|
65
|
+
#
|
|
66
|
+
# @return [self]
|
|
67
|
+
def reset!
|
|
68
|
+
@stubbed_responses.clear
|
|
69
|
+
@call_history.clear
|
|
70
|
+
@error_mode = false
|
|
71
|
+
@error_code = nil
|
|
72
|
+
@error_message = nil
|
|
73
|
+
self
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# 指定メソッドが呼び出されたかチェック
|
|
77
|
+
#
|
|
78
|
+
# @param method_name [Symbol, String] メソッド名
|
|
79
|
+
# @return [Boolean]
|
|
80
|
+
def called?(method_name)
|
|
81
|
+
@call_history.any? { |c| c[:method] == method_name.to_sym }
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# 指定メソッドの呼び出し回数を取得
|
|
85
|
+
#
|
|
86
|
+
# @param method_name [Symbol, String] メソッド名
|
|
87
|
+
# @return [Integer]
|
|
88
|
+
def call_count(method_name)
|
|
89
|
+
@call_history.count { |c| c[:method] == method_name.to_sym }
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# 指定メソッドの最後の呼び出し引数を取得
|
|
93
|
+
#
|
|
94
|
+
# @param method_name [Symbol, String] メソッド名
|
|
95
|
+
# @return [Hash, nil]
|
|
96
|
+
def last_call_args(method_name)
|
|
97
|
+
@call_history.reverse.find { |c| c[:method] == method_name.to_sym }&.[](:args)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# 強制インポートモード(本物と同じインターフェース)
|
|
101
|
+
def force_import
|
|
102
|
+
@wait_flag = true
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def method_missing(method_name, args = {})
|
|
106
|
+
@call_history << { method: method_name.to_sym, args: args, time: Time.now }
|
|
107
|
+
|
|
108
|
+
if @error_mode
|
|
109
|
+
raise NeAPIException, "#{@error_code}:#{@error_message}"
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
if @stubbed_responses.key?(method_name.to_sym)
|
|
113
|
+
result = @stubbed_responses[method_name.to_sym].call(args)
|
|
114
|
+
wrap_response(result, method_name)
|
|
115
|
+
else
|
|
116
|
+
default_response(method_name, args)
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def respond_to_missing?(method_name, include_private = false)
|
|
121
|
+
true
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
private
|
|
125
|
+
|
|
126
|
+
def wrap_response(data, method_name)
|
|
127
|
+
# 既にHash形式でresultキーがある場合はそのまま返す
|
|
128
|
+
return data if data.is_a?(Hash) && data.key?("result")
|
|
129
|
+
|
|
130
|
+
method_type = method_name.to_s.split("_").last
|
|
131
|
+
case method_type
|
|
132
|
+
when "search"
|
|
133
|
+
# searchはdataキーの値を直接返す
|
|
134
|
+
data
|
|
135
|
+
when "count"
|
|
136
|
+
data.is_a?(Integer) ? data.to_s : data
|
|
137
|
+
else
|
|
138
|
+
data
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def default_response(method_name, args)
|
|
143
|
+
method_type = method_name.to_s.split("_").last
|
|
144
|
+
case method_type
|
|
145
|
+
when "search"
|
|
146
|
+
[]
|
|
147
|
+
when "count"
|
|
148
|
+
"0"
|
|
149
|
+
when "info"
|
|
150
|
+
{
|
|
151
|
+
"result" => "success",
|
|
152
|
+
"data" => [],
|
|
153
|
+
"count" => "0",
|
|
154
|
+
"access_token" => @access_token,
|
|
155
|
+
"refresh_token" => @refresh_token
|
|
156
|
+
}
|
|
157
|
+
when "update", "upload", "receipted", "shipped", "labelprinted", "add", "bulkupdate", "bulkupdatereceipted"
|
|
158
|
+
"success"
|
|
159
|
+
when "divide"
|
|
160
|
+
"new_receive_order_id"
|
|
161
|
+
when "checkconnect"
|
|
162
|
+
{
|
|
163
|
+
"result" => "success",
|
|
164
|
+
"access_token" => @access_token,
|
|
165
|
+
"refresh_token" => @refresh_token
|
|
166
|
+
}
|
|
167
|
+
else
|
|
168
|
+
{
|
|
169
|
+
"result" => "success",
|
|
170
|
+
"access_token" => @access_token,
|
|
171
|
+
"refresh_token" => @refresh_token
|
|
172
|
+
}
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
end
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
require 'securerandom'
|
|
2
|
+
|
|
3
|
+
module NeAPI
|
|
4
|
+
module Testing
|
|
5
|
+
# テスト用レスポンスデータを生成するファクトリ
|
|
6
|
+
#
|
|
7
|
+
# @example 商品データ生成
|
|
8
|
+
# ResponseFactory.goods(goods_name: "テスト商品A")
|
|
9
|
+
# ResponseFactory.goods_list(3)
|
|
10
|
+
#
|
|
11
|
+
# @example 受注データ生成
|
|
12
|
+
# ResponseFactory.receive_order(receive_order_total_amount: 5000)
|
|
13
|
+
#
|
|
14
|
+
class ResponseFactory
|
|
15
|
+
class << self
|
|
16
|
+
# 商品マスタデータを生成
|
|
17
|
+
#
|
|
18
|
+
# @param overrides [Hash] 上書きする属性
|
|
19
|
+
# @return [Hash]
|
|
20
|
+
def goods(overrides = {})
|
|
21
|
+
{
|
|
22
|
+
"goods_id" => SecureRandom.hex(8),
|
|
23
|
+
"goods_name" => "テスト商品",
|
|
24
|
+
"goods_jan_code" => "4912345678901"
|
|
25
|
+
}.merge(stringify_keys(overrides))
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# 商品リストを生成
|
|
29
|
+
#
|
|
30
|
+
# @param count [Integer] 生成数
|
|
31
|
+
# @yield [item, index] 各アイテムをカスタマイズするブロック
|
|
32
|
+
# @return [Array<Hash>]
|
|
33
|
+
def goods_list(count = 3, &block)
|
|
34
|
+
count.times.map do |i|
|
|
35
|
+
item = goods("goods_id" => "GOODS#{format('%03d', i + 1)}", "goods_name" => "テスト商品#{i + 1}")
|
|
36
|
+
block ? block.call(item, i) : item
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# 在庫マスタデータを生成
|
|
41
|
+
#
|
|
42
|
+
# @param overrides [Hash] 上書きする属性
|
|
43
|
+
# @return [Hash]
|
|
44
|
+
def stock(overrides = {})
|
|
45
|
+
{
|
|
46
|
+
"stock_goods_id" => SecureRandom.hex(8),
|
|
47
|
+
"stock_quantity" => 100,
|
|
48
|
+
"stock_allocation_quantity" => 10,
|
|
49
|
+
"stock_defective_quantity" => 0,
|
|
50
|
+
"stock_remaining_order_quantity" => 0,
|
|
51
|
+
"stock_out_quantity" => 0,
|
|
52
|
+
"stock_free_quantity" => 90
|
|
53
|
+
}.merge(stringify_keys(overrides))
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# 在庫リストを生成
|
|
57
|
+
#
|
|
58
|
+
# @param count [Integer] 生成数
|
|
59
|
+
# @return [Array<Hash>]
|
|
60
|
+
def stock_list(count = 3, &block)
|
|
61
|
+
count.times.map do |i|
|
|
62
|
+
item = stock("stock_goods_id" => "GOODS#{format('%03d', i + 1)}")
|
|
63
|
+
block ? block.call(item, i) : item
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# 受注データを生成
|
|
68
|
+
#
|
|
69
|
+
# @param overrides [Hash] 上書きする属性
|
|
70
|
+
# @return [Hash]
|
|
71
|
+
def receive_order(overrides = {})
|
|
72
|
+
{
|
|
73
|
+
"receive_order_id" => SecureRandom.hex(8),
|
|
74
|
+
"receive_order_shop_id" => "1",
|
|
75
|
+
"receive_order_shop_cut_form_id" => "ORD-#{SecureRandom.hex(4).upcase}",
|
|
76
|
+
"receive_order_date" => Time.now.strftime("%Y-%m-%d %H:%M:%S"),
|
|
77
|
+
"receive_order_order_status_id" => "10",
|
|
78
|
+
"receive_order_order_status_name" => "新規受付",
|
|
79
|
+
"receive_order_delivery_id" => "1",
|
|
80
|
+
"receive_order_delivery_name" => "ヤマト運輸",
|
|
81
|
+
"receive_order_payment_method_id" => "1",
|
|
82
|
+
"receive_order_payment_method_name" => "クレジットカード",
|
|
83
|
+
"receive_order_total_amount" => 1000,
|
|
84
|
+
"receive_order_tax_amount" => 100,
|
|
85
|
+
"receive_order_goods_amount" => 900,
|
|
86
|
+
"receive_order_delivery_fee_amount" => 0,
|
|
87
|
+
"receive_order_purchaser_name" => "テスト顧客",
|
|
88
|
+
"receive_order_purchaser_kana" => "テストコキャク",
|
|
89
|
+
"receive_order_purchaser_zip_code" => "100-0001",
|
|
90
|
+
"receive_order_purchaser_address1" => "東京都千代田区",
|
|
91
|
+
"receive_order_purchaser_address2" => "1-1-1",
|
|
92
|
+
"receive_order_purchaser_tel" => "03-1234-5678",
|
|
93
|
+
"receive_order_purchaser_mail_address" => "test@example.com",
|
|
94
|
+
"receive_order_consignee_name" => "テスト顧客",
|
|
95
|
+
"receive_order_consignee_zip_code" => "100-0001",
|
|
96
|
+
"receive_order_consignee_address1" => "東京都千代田区",
|
|
97
|
+
"receive_order_consignee_address2" => "1-1-1",
|
|
98
|
+
"receive_order_consignee_tel" => "03-1234-5678"
|
|
99
|
+
}.merge(stringify_keys(overrides))
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# 受注リストを生成
|
|
103
|
+
#
|
|
104
|
+
# @param count [Integer] 生成数
|
|
105
|
+
# @return [Array<Hash>]
|
|
106
|
+
def receive_order_list(count = 3, &block)
|
|
107
|
+
count.times.map do |i|
|
|
108
|
+
item = receive_order("receive_order_shop_cut_form_id" => "ORD-#{format('%04d', i + 1)}")
|
|
109
|
+
block ? block.call(item, i) : item
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# 受注明細データを生成
|
|
114
|
+
#
|
|
115
|
+
# @param overrides [Hash] 上書きする属性
|
|
116
|
+
# @return [Hash]
|
|
117
|
+
def receive_order_row(overrides = {})
|
|
118
|
+
{
|
|
119
|
+
"receive_order_row_receive_order_id" => SecureRandom.hex(8),
|
|
120
|
+
"receive_order_row_no" => "1",
|
|
121
|
+
"receive_order_row_goods_id" => SecureRandom.hex(8),
|
|
122
|
+
"receive_order_row_goods_name" => "テスト商品",
|
|
123
|
+
"receive_order_row_quantity" => 1,
|
|
124
|
+
"receive_order_row_unit_price" => 1000,
|
|
125
|
+
"receive_order_row_goods_option" => ""
|
|
126
|
+
}.merge(stringify_keys(overrides))
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
# 会社情報を生成
|
|
130
|
+
#
|
|
131
|
+
# @param overrides [Hash] 上書きする属性
|
|
132
|
+
# @return [Hash]
|
|
133
|
+
def company_info(overrides = {})
|
|
134
|
+
{
|
|
135
|
+
"company_id" => "12345",
|
|
136
|
+
"company_name" => "テスト会社",
|
|
137
|
+
"company_ne_id" => "NE123456",
|
|
138
|
+
"company_kana" => "テストカイシャ"
|
|
139
|
+
}.merge(stringify_keys(overrides))
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
# ユーザー情報を生成
|
|
143
|
+
#
|
|
144
|
+
# @param overrides [Hash] 上書きする属性
|
|
145
|
+
# @return [Hash]
|
|
146
|
+
def user_info(overrides = {})
|
|
147
|
+
{
|
|
148
|
+
"user_id" => "1",
|
|
149
|
+
"user_name" => "テストユーザー",
|
|
150
|
+
"user_mail" => "test@example.com"
|
|
151
|
+
}.merge(stringify_keys(overrides))
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
# 店舗データを生成
|
|
155
|
+
#
|
|
156
|
+
# @param overrides [Hash] 上書きする属性
|
|
157
|
+
# @return [Hash]
|
|
158
|
+
def shop(overrides = {})
|
|
159
|
+
{
|
|
160
|
+
"shop_id" => "1",
|
|
161
|
+
"shop_name" => "テスト店舗",
|
|
162
|
+
"shop_kana" => "テストテンポ",
|
|
163
|
+
"shop_abbreviated_name" => "テスト",
|
|
164
|
+
"shop_mall_id" => "1",
|
|
165
|
+
"shop_deleted_flag" => "0"
|
|
166
|
+
}.merge(stringify_keys(overrides))
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
# 倉庫在庫データを生成
|
|
170
|
+
#
|
|
171
|
+
# @param overrides [Hash] 上書きする属性
|
|
172
|
+
# @return [Hash]
|
|
173
|
+
def warehouse_stock(overrides = {})
|
|
174
|
+
{
|
|
175
|
+
"warehouse_stock_warehouse_id" => "1",
|
|
176
|
+
"warehouse_stock_goods_id" => SecureRandom.hex(8),
|
|
177
|
+
"warehouse_stock_quantity" => 100,
|
|
178
|
+
"warehouse_stock_allocation_quantity" => 10,
|
|
179
|
+
"warehouse_stock_free_quantity" => 90
|
|
180
|
+
}.merge(stringify_keys(overrides))
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
# エラーレスポンスを生成
|
|
184
|
+
#
|
|
185
|
+
# @param code [String] エラーコード
|
|
186
|
+
# @param message [String] エラーメッセージ
|
|
187
|
+
# @return [Hash]
|
|
188
|
+
def error(code: "001001", message: "エラーが発生しました")
|
|
189
|
+
{
|
|
190
|
+
"result" => "error",
|
|
191
|
+
"code" => code,
|
|
192
|
+
"message" => message
|
|
193
|
+
}
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
# 混雑エラー(リトライ対象)を生成
|
|
197
|
+
#
|
|
198
|
+
# @return [Hash]
|
|
199
|
+
def busy_error
|
|
200
|
+
error(code: "003001", message: "Next Engineが大変混み合っています")
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
# 成功レスポンスを生成(info系API用)
|
|
204
|
+
#
|
|
205
|
+
# @param data [Array] データ配列
|
|
206
|
+
# @param access_token [String] アクセストークン
|
|
207
|
+
# @param refresh_token [String] リフレッシュトークン
|
|
208
|
+
# @return [Hash]
|
|
209
|
+
def success_response(data: [], access_token: "test_access_token", refresh_token: "test_refresh_token")
|
|
210
|
+
{
|
|
211
|
+
"result" => "success",
|
|
212
|
+
"data" => data,
|
|
213
|
+
"count" => data.size.to_s,
|
|
214
|
+
"access_token" => access_token,
|
|
215
|
+
"refresh_token" => refresh_token
|
|
216
|
+
}
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
private
|
|
220
|
+
|
|
221
|
+
def stringify_keys(hash)
|
|
222
|
+
hash.transform_keys(&:to_s)
|
|
223
|
+
end
|
|
224
|
+
end
|
|
225
|
+
end
|
|
226
|
+
end
|
|
227
|
+
end
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
module NeAPI
|
|
2
|
+
module Testing
|
|
3
|
+
# RSpec用ヘルパーメソッド
|
|
4
|
+
#
|
|
5
|
+
# @example spec/rails_helper.rb での設定
|
|
6
|
+
# require 'ne_api/testing'
|
|
7
|
+
#
|
|
8
|
+
# RSpec.configure do |config|
|
|
9
|
+
# config.include NeAPI::Testing::RSpecHelpers
|
|
10
|
+
# end
|
|
11
|
+
#
|
|
12
|
+
# @example テストコードでの使用
|
|
13
|
+
# RSpec.describe OrderService do
|
|
14
|
+
# it "受注を取得する" do
|
|
15
|
+
# with_fake_ne_api do |fake|
|
|
16
|
+
# fake.stub(:receiveorder_base_search, [ne_receive_order])
|
|
17
|
+
# # ...
|
|
18
|
+
# end
|
|
19
|
+
# end
|
|
20
|
+
# end
|
|
21
|
+
#
|
|
22
|
+
module RSpecHelpers
|
|
23
|
+
# FakeMasterインスタンスを生成
|
|
24
|
+
#
|
|
25
|
+
# @param options [Hash] 初期化オプション
|
|
26
|
+
# @return [FakeMaster]
|
|
27
|
+
def fake_ne_master(**options)
|
|
28
|
+
NeAPI::Testing::FakeMaster.new(**options)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# FakeAuthインスタンスを生成
|
|
32
|
+
#
|
|
33
|
+
# @param options [Hash] 初期化オプション
|
|
34
|
+
# @return [FakeAuth]
|
|
35
|
+
def fake_ne_auth(**options)
|
|
36
|
+
NeAPI::Testing::FakeAuth.new(**options)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# NeAPI::Master.newをFakeMasterに差し替えてブロックを実行
|
|
40
|
+
#
|
|
41
|
+
# @yield [FakeMaster] FakeMasterインスタンス
|
|
42
|
+
# @return [Object] ブロックの戻り値
|
|
43
|
+
#
|
|
44
|
+
# @example
|
|
45
|
+
# with_fake_ne_api do |fake|
|
|
46
|
+
# fake.stub(:master_goods_search, [ne_goods])
|
|
47
|
+
# service = MyService.new # 内部でNeAPI::Master.newを呼ぶ
|
|
48
|
+
# service.call
|
|
49
|
+
# end
|
|
50
|
+
def with_fake_ne_api(**options)
|
|
51
|
+
fake = fake_ne_master(**options)
|
|
52
|
+
allow(NeAPI::Master).to receive(:new).and_return(fake)
|
|
53
|
+
yield fake
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# NeAPI::Auth.newをFakeAuthに差し替えてブロックを実行
|
|
57
|
+
#
|
|
58
|
+
# @yield [FakeAuth] FakeAuthインスタンス
|
|
59
|
+
# @return [Object] ブロックの戻り値
|
|
60
|
+
def with_fake_ne_auth(**options)
|
|
61
|
+
fake = fake_ne_auth(**options)
|
|
62
|
+
allow(NeAPI::Auth).to receive(:new).and_return(fake)
|
|
63
|
+
yield fake
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# --- ResponseFactoryへのショートカット ---
|
|
67
|
+
|
|
68
|
+
# 商品データを生成
|
|
69
|
+
# @see ResponseFactory.goods
|
|
70
|
+
def ne_goods(**attrs)
|
|
71
|
+
NeAPI::Testing::ResponseFactory.goods(attrs)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# 商品リストを生成
|
|
75
|
+
# @see ResponseFactory.goods_list
|
|
76
|
+
def ne_goods_list(count = 3, &block)
|
|
77
|
+
NeAPI::Testing::ResponseFactory.goods_list(count, &block)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# 在庫データを生成
|
|
81
|
+
# @see ResponseFactory.stock
|
|
82
|
+
def ne_stock(**attrs)
|
|
83
|
+
NeAPI::Testing::ResponseFactory.stock(attrs)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# 在庫リストを生成
|
|
87
|
+
# @see ResponseFactory.stock_list
|
|
88
|
+
def ne_stock_list(count = 3, &block)
|
|
89
|
+
NeAPI::Testing::ResponseFactory.stock_list(count, &block)
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# 受注データを生成
|
|
93
|
+
# @see ResponseFactory.receive_order
|
|
94
|
+
def ne_receive_order(**attrs)
|
|
95
|
+
NeAPI::Testing::ResponseFactory.receive_order(attrs)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# 受注リストを生成
|
|
99
|
+
# @see ResponseFactory.receive_order_list
|
|
100
|
+
def ne_receive_order_list(count = 3, &block)
|
|
101
|
+
NeAPI::Testing::ResponseFactory.receive_order_list(count, &block)
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
# 受注明細データを生成
|
|
105
|
+
# @see ResponseFactory.receive_order_row
|
|
106
|
+
def ne_receive_order_row(**attrs)
|
|
107
|
+
NeAPI::Testing::ResponseFactory.receive_order_row(attrs)
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# 会社情報を生成
|
|
111
|
+
# @see ResponseFactory.company_info
|
|
112
|
+
def ne_company_info(**attrs)
|
|
113
|
+
NeAPI::Testing::ResponseFactory.company_info(attrs)
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# ユーザー情報を生成
|
|
117
|
+
# @see ResponseFactory.user_info
|
|
118
|
+
def ne_user_info(**attrs)
|
|
119
|
+
NeAPI::Testing::ResponseFactory.user_info(attrs)
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
# 店舗データを生成
|
|
123
|
+
# @see ResponseFactory.shop
|
|
124
|
+
def ne_shop(**attrs)
|
|
125
|
+
NeAPI::Testing::ResponseFactory.shop(attrs)
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# 倉庫在庫データを生成
|
|
129
|
+
# @see ResponseFactory.warehouse_stock
|
|
130
|
+
def ne_warehouse_stock(**attrs)
|
|
131
|
+
NeAPI::Testing::ResponseFactory.warehouse_stock(attrs)
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# エラーレスポンスを生成
|
|
135
|
+
# @see ResponseFactory.error
|
|
136
|
+
def ne_error(**attrs)
|
|
137
|
+
NeAPI::Testing::ResponseFactory.error(**attrs)
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
# 成功レスポンスを生成
|
|
141
|
+
# @see ResponseFactory.success_response
|
|
142
|
+
def ne_success_response(**attrs)
|
|
143
|
+
NeAPI::Testing::ResponseFactory.success_response(**attrs)
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
# RSpecが読み込まれていれば自動設定
|
|
150
|
+
if defined?(RSpec)
|
|
151
|
+
RSpec.configure do |config|
|
|
152
|
+
config.include NeAPI::Testing::RSpecHelpers
|
|
153
|
+
end
|
|
154
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# ne_api テスト用スタブ
|
|
2
|
+
#
|
|
3
|
+
# Railsプロジェクトでの設定:
|
|
4
|
+
#
|
|
5
|
+
# # spec/rails_helper.rb
|
|
6
|
+
# require 'ne_api/testing'
|
|
7
|
+
#
|
|
8
|
+
# RSpec.configure do |config|
|
|
9
|
+
# config.include NeAPI::Testing::RSpecHelpers
|
|
10
|
+
# end
|
|
11
|
+
#
|
|
12
|
+
# 使用例:
|
|
13
|
+
#
|
|
14
|
+
# RSpec.describe OrderSyncService do
|
|
15
|
+
# it "受注を同期する" do
|
|
16
|
+
# with_fake_ne_api do |fake|
|
|
17
|
+
# fake.stub(:receiveorder_base_search, [
|
|
18
|
+
# ne_receive_order(receive_order_id: "ORDER001")
|
|
19
|
+
# ])
|
|
20
|
+
#
|
|
21
|
+
# service = OrderSyncService.new(ne_api: fake)
|
|
22
|
+
# result = service.sync
|
|
23
|
+
#
|
|
24
|
+
# expect(result.count).to eq 1
|
|
25
|
+
# expect(fake.called?(:receiveorder_base_search)).to be true
|
|
26
|
+
# end
|
|
27
|
+
# end
|
|
28
|
+
# end
|
|
29
|
+
|
|
30
|
+
require_relative 'testing/fake_master'
|
|
31
|
+
require_relative 'testing/fake_auth'
|
|
32
|
+
require_relative 'testing/response_factory'
|
|
33
|
+
require_relative 'testing/rspec_helpers'
|
|
34
|
+
|
|
35
|
+
module NeAPI
|
|
36
|
+
module Testing
|
|
37
|
+
class << self
|
|
38
|
+
# 設定用ブロック(将来の拡張用)
|
|
39
|
+
def configure
|
|
40
|
+
yield self if block_given?
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
data/lib/ne_api/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ne_api
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0.
|
|
4
|
+
version: 0.0.21
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Yuuna Kurita
|
|
8
8
|
- Mika Koizumi
|
|
9
|
-
autorequire:
|
|
10
9
|
bindir: bin
|
|
11
10
|
cert_chain: []
|
|
12
|
-
date:
|
|
11
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
13
12
|
dependencies:
|
|
14
13
|
- !ruby/object:Gem::Dependency
|
|
15
14
|
name: bundler
|
|
@@ -152,6 +151,11 @@ files:
|
|
|
152
151
|
- Rakefile
|
|
153
152
|
- config/api.yaml
|
|
154
153
|
- lib/ne_api.rb
|
|
154
|
+
- lib/ne_api/testing.rb
|
|
155
|
+
- lib/ne_api/testing/fake_auth.rb
|
|
156
|
+
- lib/ne_api/testing/fake_master.rb
|
|
157
|
+
- lib/ne_api/testing/response_factory.rb
|
|
158
|
+
- lib/ne_api/testing/rspec_helpers.rb
|
|
155
159
|
- lib/ne_api/version.rb
|
|
156
160
|
- ne_api.gemspec
|
|
157
161
|
- spec/ne_api_spec.rb
|
|
@@ -159,7 +163,6 @@ homepage: http://github.com/infinity-octaver/ne_api/
|
|
|
159
163
|
licenses:
|
|
160
164
|
- MIT
|
|
161
165
|
metadata: {}
|
|
162
|
-
post_install_message:
|
|
163
166
|
rdoc_options: []
|
|
164
167
|
require_paths:
|
|
165
168
|
- lib
|
|
@@ -174,8 +177,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
174
177
|
- !ruby/object:Gem::Version
|
|
175
178
|
version: '0'
|
|
176
179
|
requirements: []
|
|
177
|
-
rubygems_version:
|
|
178
|
-
signing_key:
|
|
180
|
+
rubygems_version: 4.0.1
|
|
179
181
|
specification_version: 4
|
|
180
182
|
summary: Next Engine API for ruby
|
|
181
183
|
test_files:
|