rspec_magic 0.1.2
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 +7 -0
- data/.gitignore +26 -0
- data/.rspec +3 -0
- data/.yardopts +7 -0
- data/Gemfile +8 -0
- data/Gemfile.lock +36 -0
- data/MIT-LICENSE +20 -0
- data/README-ru.md +328 -0
- data/README.md +328 -0
- data/Rakefile +15 -0
- data/lib/rspec_magic/config.rb +17 -0
- data/lib/rspec_magic/stable/alias_method.rb +26 -0
- data/lib/rspec_magic/stable/context_when.rb +101 -0
- data/lib/rspec_magic/stable/described_sym.rb +62 -0
- data/lib/rspec_magic/stable/use_letset.rb +95 -0
- data/lib/rspec_magic/stable/use_method_discovery.rb +75 -0
- data/lib/rspec_magic/stable.rb +13 -0
- data/lib/rspec_magic/unstable/include_dir_context.rb +39 -0
- data/lib/rspec_magic/unstable.rb +13 -0
- data/lib/rspec_magic/version.rb +5 -0
- data/lib/rspec_magic.rb +11 -0
- data/rspec_magic.gemspec +17 -0
- data/spec/lib/rspec_magic/alias_method_spec.rb +19 -0
- data/spec/lib/rspec_magic/context_when_spec.rb +45 -0
- data/spec/lib/rspec_magic/described_sym_spec.rb +39 -0
- data/spec/lib/rspec_magic/include_dir_context/README.md +2 -0
- data/spec/lib/rspec_magic/include_dir_context/_context.rb +4 -0
- data/spec/lib/rspec_magic/include_dir_context/app/_context.rb +4 -0
- data/spec/lib/rspec_magic/include_dir_context/app/idc_consumer_spec.rb +15 -0
- data/spec/lib/rspec_magic/include_dir_context/app/models/_context.rb +4 -0
- data/spec/lib/rspec_magic/include_dir_context/app/models/idc_consumer_spec.rb +15 -0
- data/spec/lib/rspec_magic/include_dir_context/idc_consumer_spec.rb +15 -0
- data/spec/lib/rspec_magic/use_letset_spec.rb +134 -0
- data/spec/lib/rspec_magic/use_method_discovery_spec.rb +24 -0
- data/spec/spec_helper.rb +9 -0
- data/spec/support/self.rb +6 -0
- data/spec/support/simplecov.rb +11 -0
- metadata +80 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 04d4ef834d4220f6b1aa7de8211f9f7c8aa1dc1b
|
4
|
+
data.tar.gz: ef3362accf8c7ebea8f7433b5f45e28d972c4800
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b5433ad24ae7fc8b4e7899e42ee544066f0e0848f1a652d9f7c53e34ab002012aadcc94de4e037a6033b1859d04a5ded5e91315aade3cc6ce81f380627af3051
|
7
|
+
data.tar.gz: 2ace60aec6d6376e0077045d1e023a131f7688e04520e72cacf32818583ca66fd50ff166a51c9d0eb7440017580a3421bd6435e0aaae26b0c21d8a1fe3bbb9af
|
data/.gitignore
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
|
2
|
+
# General Ruby, sorted by first letter.
|
3
|
+
/.bundle/
|
4
|
+
/coverage/
|
5
|
+
/doc/
|
6
|
+
/vendor/bundle/
|
7
|
+
/.yardoc/
|
8
|
+
|
9
|
+
# Project-specific.
|
10
|
+
/*.gem
|
11
|
+
|
12
|
+
# Old etc.
|
13
|
+
*.old*
|
14
|
+
*.orig
|
15
|
+
/*.patch
|
16
|
+
*.ref*
|
17
|
+
|
18
|
+
# Nonpersistent stuff.
|
19
|
+
TODO.md
|
20
|
+
|
21
|
+
# Shared VS Code settings.
|
22
|
+
/.vscode/*
|
23
|
+
!/.vscode/*.json
|
24
|
+
|
25
|
+
# Custom VS Code settings.
|
26
|
+
/*.code-workspace
|
data/.rspec
ADDED
data/.yardopts
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
GEM
|
2
|
+
remote: https://rubygems.org/
|
3
|
+
specs:
|
4
|
+
diff-lcs (1.5.0)
|
5
|
+
docile (1.3.5)
|
6
|
+
json (2.6.3)
|
7
|
+
rspec (3.12.0)
|
8
|
+
rspec-core (~> 3.12.0)
|
9
|
+
rspec-expectations (~> 3.12.0)
|
10
|
+
rspec-mocks (~> 3.12.0)
|
11
|
+
rspec-core (3.12.2)
|
12
|
+
rspec-support (~> 3.12.0)
|
13
|
+
rspec-expectations (3.12.3)
|
14
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
15
|
+
rspec-support (~> 3.12.0)
|
16
|
+
rspec-mocks (3.12.6)
|
17
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
18
|
+
rspec-support (~> 3.12.0)
|
19
|
+
rspec-support (3.12.1)
|
20
|
+
simplecov (0.17.1)
|
21
|
+
docile (~> 1.1)
|
22
|
+
json (>= 1.8, < 3)
|
23
|
+
simplecov-html (~> 0.10.0)
|
24
|
+
simplecov-html (0.10.2)
|
25
|
+
yard (0.9.34)
|
26
|
+
|
27
|
+
PLATFORMS
|
28
|
+
ruby
|
29
|
+
|
30
|
+
DEPENDENCIES
|
31
|
+
rspec
|
32
|
+
simplecov
|
33
|
+
yard
|
34
|
+
|
35
|
+
BUNDLED WITH
|
36
|
+
1.17.3
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2017-2024 Alex Fortuna
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README-ru.md
ADDED
@@ -0,0 +1,328 @@
|
|
1
|
+
|
2
|
+
# Немного магии для RSpec-тестов
|
3
|
+
|
4
|
+
<!-- @import "[TOC]" {cmd="toc" depthFrom=2 depthTo=6 orderedList=false} -->
|
5
|
+
|
6
|
+
<!-- code_chunk_output -->
|
7
|
+
|
8
|
+
- [Что это?](#что-это)
|
9
|
+
- [Установка](#установка)
|
10
|
+
- [Фичи](#фичи)
|
11
|
+
- [`alias_method`](#alias_method)
|
12
|
+
- [`context_when`](#context_when)
|
13
|
+
- [`described_sym`](#described_sym)
|
14
|
+
- [`include_dir_context`](#include_dir_context)
|
15
|
+
- [`use_letset`](#use_letset)
|
16
|
+
- [`use_method_discovery`](#use_method_discovery)
|
17
|
+
- [Подробно](#подробно)
|
18
|
+
- [Про установку](#про-установку)
|
19
|
+
- [Про `context_when`](#про-context_when)
|
20
|
+
- [Про `include_dir_context`](#про-include_dir_context)
|
21
|
+
- [Copyright](#copyright)
|
22
|
+
|
23
|
+
<!-- /code_chunk_output -->
|
24
|
+
|
25
|
+
## Что это?
|
26
|
+
|
27
|
+
🆎 *An English version of this text is also available: [README.md](README.md).*
|
28
|
+
|
29
|
+
RSpecMagic — набор расширений для написания компактных и выразительных тестов.
|
30
|
+
|
31
|
+
## Установка
|
32
|
+
|
33
|
+
> 💡 *Предполагается, что RSpec в нашем проекте мы уже настроили.*
|
34
|
+
|
35
|
+
Добавляем в `Gemfile`:
|
36
|
+
|
37
|
+
```ruby
|
38
|
+
gem "rspec_magic"
|
39
|
+
#gem "rspec_magic", git: "https://github.com/dadooda/rspec_magic"
|
40
|
+
```
|
41
|
+
|
42
|
+
Добавляем в автозагрузку RSpec (обычно это `spec/spec_helper.rb`):
|
43
|
+
|
44
|
+
```ruby
|
45
|
+
require "rspec_magic/stable"
|
46
|
+
require "rspec_magic/unstable"
|
47
|
+
|
48
|
+
RSpecMagic::Config.spec_path = File.expand_path(".", __dir__)
|
49
|
+
```
|
50
|
+
|
51
|
+
Настройка `spec_path` нужна для некоторых фич, например, [include_dir_context](#include_dir_context).
|
52
|
+
Вычисленный путь должен указывать на `spec/` в директории проекта.
|
53
|
+
|
54
|
+
См. [Подробно](#про-установку).
|
55
|
+
|
56
|
+
## Фичи
|
57
|
+
|
58
|
+
### `alias_method`
|
59
|
+
|
60
|
+
Matcher, сверяющий, что метод является alias'ом другого метода.
|
61
|
+
|
62
|
+
```ruby
|
63
|
+
describe User do
|
64
|
+
it { is_expected.to alias_method(:admin?, :is_admin) }
|
65
|
+
end
|
66
|
+
```
|
67
|
+
|
68
|
+
### `context_when`
|
69
|
+
|
70
|
+
Создаём стереотипный контекст, задающий внутри себя одну или несколько `let`-переменных.
|
71
|
+
Блоки ниже взаимозаменяемы.
|
72
|
+
|
73
|
+
```ruby
|
74
|
+
context_when name: "Joe", age: 25 do
|
75
|
+
it do
|
76
|
+
expect([name, age]).to eq ["Joe", 25]
|
77
|
+
end
|
78
|
+
end
|
79
|
+
```
|
80
|
+
|
81
|
+
```ruby
|
82
|
+
context "when { name: \"Joe\", age: 25 }" do
|
83
|
+
let(:name) { "Joe" }
|
84
|
+
let(:age) { 25 }
|
85
|
+
it do
|
86
|
+
expect([name, age]).to eq ["Joe", 25]
|
87
|
+
end
|
88
|
+
end
|
89
|
+
```
|
90
|
+
|
91
|
+
См. [Подробно](#про-context_when).
|
92
|
+
|
93
|
+
### `described_sym`
|
94
|
+
|
95
|
+
`described_sym` и `me` — представление имени `described_class` в виде `Symbol`.
|
96
|
+
Помогает не «долдонить» мнемоническим названием тестируемого класса, например,
|
97
|
+
при создании записей с помощью factory.
|
98
|
+
|
99
|
+
```ruby
|
100
|
+
describe UserProfile do
|
101
|
+
it { expect(described_sym).to eq :user_profile }
|
102
|
+
it { expect(me).to eq :user_profile }
|
103
|
+
end
|
104
|
+
```
|
105
|
+
|
106
|
+
С factory:
|
107
|
+
|
108
|
+
```ruby
|
109
|
+
describe UserProfile do
|
110
|
+
let(:uprof1) { create described_sym }
|
111
|
+
let(:uprof2) { create me }
|
112
|
+
…
|
113
|
+
end
|
114
|
+
```
|
115
|
+
|
116
|
+
### `include_dir_context`
|
117
|
+
|
118
|
+
♒︎ *Эта фича добавлена недавно и может измениться.*
|
119
|
+
|
120
|
+
Организуем общие контексты ([shared_context](https://rspec.info/features/3-12/rspec-core/example-groups/shared-context/)) в иерархии.
|
121
|
+
Автоматически включаем нужные общие контексты в наш тест.
|
122
|
+
|
123
|
+
Шаги:
|
124
|
+
|
125
|
+
1. Убеждаемся, что в настройках правильно прописана `RSpecMagic::Config.spec_path`.
|
126
|
+
Она должна указывать на `spec/`.
|
127
|
+
|
128
|
+
2. По файловому дереву тестов создаём файлы общих контекстов *с одинаковым именем,* например, `_context.rb`.
|
129
|
+
Содержимое `_context.rb` всегда имеет вид:
|
130
|
+
|
131
|
+
```ruby
|
132
|
+
shared_context __dir__ do
|
133
|
+
…
|
134
|
+
end
|
135
|
+
```
|
136
|
+
|
137
|
+
3. Добавляем в условный `spec_helper.rb`:
|
138
|
+
|
139
|
+
```ruby
|
140
|
+
# Загружаем иерархию shared contexts.
|
141
|
+
Dir[File.expand_path("**/_context.rb", __dir__)].each { |fn| require fn }
|
142
|
+
```
|
143
|
+
|
144
|
+
4. В spec-файле добавляем вызов `include_dir_context` в тело главного `describe`:
|
145
|
+
|
146
|
+
```ruby
|
147
|
+
describe … do
|
148
|
+
include_dir_context __dir__
|
149
|
+
…
|
150
|
+
end
|
151
|
+
```
|
152
|
+
|
153
|
+
Например, наш spec-файл это `spec/app/controllers/api/player_controller_spec.rb`.
|
154
|
+
|
155
|
+
В главный `describe` будут последовательно загружены, *если они есть,* контексты из файлов:
|
156
|
+
|
157
|
+
```
|
158
|
+
spec/_context.rb
|
159
|
+
spec/app/_context.rb
|
160
|
+
spec/app/controllers/_context.rb
|
161
|
+
spec/app/controllers/api/_context.rb
|
162
|
+
```
|
163
|
+
|
164
|
+
См. [Подробно](#про-include_dir_context).
|
165
|
+
|
166
|
+
### `use_letset`
|
167
|
+
|
168
|
+
Создаём на уровне `describe` метод для задания `let`-переменных, автоматически составляющих коллекцию типа `Hash`.
|
169
|
+
|
170
|
+
```ruby
|
171
|
+
describe do
|
172
|
+
# Метод -- `let_a`. Коллекция -- `attrs`.
|
173
|
+
use_letset :let_a, :attrs
|
174
|
+
|
175
|
+
# Декларируем переменные, которые составляют коллекцию `attrs`.
|
176
|
+
let_a(:age)
|
177
|
+
let_a(:name)
|
178
|
+
|
179
|
+
subject { attrs }
|
180
|
+
|
181
|
+
# Ни одна переменная пока не задана, поэтому коллекция будет пустой.
|
182
|
+
it { is_expected.to eq({}) }
|
183
|
+
|
184
|
+
# Задаём `name` и видим его в коллекции.
|
185
|
+
context_when name: "Joe" do
|
186
|
+
it { is_expected.to eq(name: "Joe") }
|
187
|
+
|
188
|
+
# Задаём `age` и видим обе переменные в коллекции.
|
189
|
+
context_when age: 25 do
|
190
|
+
it { is_expected.to eq(name: "Joe", age: 25) }
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
```
|
195
|
+
|
196
|
+
Если передан блок, `let_a` работает как обычный `let`. Такой вариант изредка тоже бывает полезен:
|
197
|
+
|
198
|
+
```ruby
|
199
|
+
describe do
|
200
|
+
use_letset :let_a, :attrs
|
201
|
+
|
202
|
+
let_a(:age) { 25 }
|
203
|
+
let_a(:name) { "Joe" }
|
204
|
+
|
205
|
+
it { expect(attrs).to eq(name: "Joe", age: 25) }
|
206
|
+
end
|
207
|
+
```
|
208
|
+
|
209
|
+
### `use_method_discovery`
|
210
|
+
|
211
|
+
Создаём автоматическую `let`-переменную, содержащую имя метода или action,
|
212
|
+
вычисленное из текста вышестоящего `describe`.
|
213
|
+
|
214
|
+
```ruby
|
215
|
+
describe do
|
216
|
+
use_method_discovery :m
|
217
|
+
|
218
|
+
subject { m }
|
219
|
+
|
220
|
+
describe "#first_name" do
|
221
|
+
it { is_expected.to eq :first_name }
|
222
|
+
end
|
223
|
+
|
224
|
+
describe ".some_stuff" do
|
225
|
+
it { is_expected.to eq :some_stuff }
|
226
|
+
end
|
227
|
+
|
228
|
+
describe "GET some_action" do
|
229
|
+
describe "intermediate context" do
|
230
|
+
it { is_expected.to eq :some_action } # (1)
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|
234
|
+
```
|
235
|
+
|
236
|
+
`m` находит ближайший *подходящий* контекст, формат текста которого допускает выемку имени метода.
|
237
|
+
См. (1) — `m` пропустила вольно отформатированный `"intermediate context"` и сработала
|
238
|
+
на `"GET some_action"`.
|
239
|
+
|
240
|
+
## Подробно
|
241
|
+
|
242
|
+
### Про установку
|
243
|
+
|
244
|
+
1. `stable` и `unstable` — наборы фич. В набор `unstable` входят фичи,
|
245
|
+
добавленные недавно. Они могут измениться в следующих версиях.
|
246
|
+
|
247
|
+
2. Можно включить только конкретные фичи. Например:
|
248
|
+
|
249
|
+
```ruby
|
250
|
+
require "rspec_magic/stable/use_method_discovery"
|
251
|
+
```
|
252
|
+
|
253
|
+
### Про `context_when`
|
254
|
+
|
255
|
+
1. Контекст можно исключить из обработки, приписав к началу `x`:
|
256
|
+
|
257
|
+
```ruby
|
258
|
+
xcontext_when … do
|
259
|
+
…
|
260
|
+
end
|
261
|
+
```
|
262
|
+
|
263
|
+
2. Можно определить свой метод форматирования строки для отчёта:
|
264
|
+
|
265
|
+
```ruby
|
266
|
+
describe "…" do
|
267
|
+
def self._context_when_formatter(h)
|
268
|
+
"when #{h.to_json}"
|
269
|
+
end
|
270
|
+
|
271
|
+
context_when … do
|
272
|
+
…
|
273
|
+
end
|
274
|
+
end
|
275
|
+
```
|
276
|
+
|
277
|
+
3. `context_when` эффективно работает в паре с [use_letset](#use_letset),
|
278
|
+
обычно для задания атрибутов тестируемого объекта.
|
279
|
+
|
280
|
+
4. Значения `let`-переменных вычисляются на уровне `describe`.
|
281
|
+
Если нужны значения, вычисляемые на уровне `it`, следует использовать обычный `let(…) { … }` внутри контекста.
|
282
|
+
|
283
|
+
### Про `include_dir_context`
|
284
|
+
|
285
|
+
Есть в RSpec классная штука — общие контексты, они же [shared_context](https://rspec.info/features/3-12/rspec-core/example-groups/shared-context/).
|
286
|
+
Замысел простой: где-то (в условном `spec_helper.rb`) мы создаём нечто общее через `shared_context "то сё"`,
|
287
|
+
а потом через `include_context "то сё"` импортируем материал в нужный там тест.
|
288
|
+
|
289
|
+
Наполнять `shared_context` можно чем угодно — общими тестами, `let`-переменными, *но главное* —
|
290
|
+
методами уровня `describe` (`def self.doit`) и методами уровня `it` (`def doit`).
|
291
|
+
|
292
|
+
Чем не библиотека?
|
293
|
+
|
294
|
+
Казалось бы — вот оно счастьюшко, сочиняй свои расширения, разноси по общим контекстам, где надо импортируй и радуйся.
|
295
|
+
Но есть неприятная особенность: штатные средства организации контекстов очень примитивны и опираются на глобальные уникальные имена.
|
296
|
+
|
297
|
+
RSpec не позволяет организовывать общие контексты в иерархии,
|
298
|
+
чтобы автоматически импортировать контексты-«библиотеки» в группы spec-файлов, как то:
|
299
|
+
*всем* тестам моделей — одно, *всем* тестам контроллеров — другое, а *всем* им вместе — третье.
|
300
|
+
|
301
|
+
Чтобы поддерживать мало-мальский порядок, приходится натужно придумывать общим контекстам
|
302
|
+
уникальные имена, и *в каждом* spec-файле перечислять импортируемое унылым повторяющимся списком:
|
303
|
+
|
304
|
+
```ruby
|
305
|
+
describe … do
|
306
|
+
include_context "basic"
|
307
|
+
include_context "controllers"
|
308
|
+
include_context "api_controllers"
|
309
|
+
…
|
310
|
+
end
|
311
|
+
```
|
312
|
+
|
313
|
+
И это ещё продвинутый уровень.
|
314
|
+
Чаще всего даже так не делают, а просто сваливают все расширения в кучу и включают сразу всё,
|
315
|
+
просто потому, что «некогда разбираться».
|
316
|
+
|
317
|
+
Что даёт `include_dir_context`?
|
318
|
+
|
319
|
+
1. Возможность организовывать общие контексты в иерархии.
|
320
|
+
2. Возможность автоматически включать наборы *того, что нужно, туда, куда нужно.*
|
321
|
+
|
322
|
+
Как это делать, описано в [основной главе](#include_dir_context).
|
323
|
+
|
324
|
+
## Copyright
|
325
|
+
|
326
|
+
Продукт распространяется свободно на условиях лицензии MIT.
|
327
|
+
|
328
|
+
— © 2017-2024 Алексей Фортуна
|