rast 0.18.0 → 0.19.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +15 -0
- data/CHANGELOG.md +14 -0
- data/Documentation.md +297 -0
- data/Gemfile +0 -2
- data/Getting-Started-Detailed.md +122 -0
- data/Getting-Started.md +19 -102
- data/README.md +80 -16
- data/examples/enum_module.rb +20 -6
- data/examples/factory_example.rb +4 -4
- data/examples/hotel_finder.rb +14 -0
- data/examples/person.rb +6 -0
- data/examples/prime_number.rb +13 -8
- data/lib/rast/parameter_generator.rb +107 -53
- data/lib/rast/rast_spec.rb +8 -2
- data/lib/rast/rules/logic_helper.rb +76 -95
- data/lib/rast/rules/rule_evaluator.rb +100 -98
- data/lib/rast/rules/rule_validator.rb +14 -7
- data/lib/rast/rules/token_util.rb +17 -0
- data/lib/rast/spec_dsl.rb +57 -35
- data/lib/rast.rb +5 -1
- data/lib/template_spec.yml +5 -7
- data/rast.gemspec +1 -1
- metadata +8 -9
- data/examples/arithmetic_module.rb +0 -8
- data/examples/double_example.rb +0 -14
- data/examples/logic_four.rb +0 -15
- data/examples/lohika.rb +0 -27
- data/examples/phone.rb +0 -6
- data/examples/quiz_module.rb +0 -34
- data/examples/triple.rb +0 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3f3ab7d817085dca4c5fc3c3fd0956ca6a6f87eadd9d97554f693aa81908f5e8
|
4
|
+
data.tar.gz: 5e2f9d234c29e5cfc0ccab251980099e13af8c3355d7ea83ad3d8dc8a97ff4c1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3fe3b7af6cbc40ce1ab44a8120ac66865b262a751a448d382f72a2cc28999ab45761a21a4747b8c362e27e46e06eaf4f34f4cf794fb64951d680621c9b1a1deb
|
7
|
+
data.tar.gz: 1e07f58dd3fa04a7e84b6cf25a4b4956847f1975e21973b4b3ecc62d74c9f28b3676fd7b185224a2a65b0f4eee612efaea92999c8e8dc7dda01f312db1f825c8
|
data/.travis.yml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
language: ruby
|
3
|
+
rvm:
|
4
|
+
- 2.0.0
|
5
|
+
|
6
|
+
before_script:
|
7
|
+
- curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
|
8
|
+
- chmod +x ./cc-test-reporter
|
9
|
+
- ./cc-test-reporter before-build
|
10
|
+
|
11
|
+
script:
|
12
|
+
- bundle exec rspec
|
13
|
+
|
14
|
+
after_script:
|
15
|
+
- ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,19 @@
|
|
1
1
|
# Change log
|
2
2
|
|
3
|
+
## Unreleased
|
4
|
+
|
5
|
+
- Add travis-ci build.
|
6
|
+
- Add RubyGems badge
|
7
|
+
- Update documentation.
|
8
|
+
|
9
|
+
## Released
|
10
|
+
|
11
|
+
|
12
|
+
- 0.19.0 - [feature] boolean in variables definition to automatically infer
|
13
|
+
false and true
|
14
|
+
[feature] xrast to skip entire test.
|
15
|
+
[feature] Add default outcome in yaml-less configuration. Default
|
16
|
+
config will take higher precedence than boolean outcomes.
|
3
17
|
- 0.18.0 - [feature] xspec to skip a test
|
4
18
|
- [feature] Added include rule to isolate scenarios.
|
5
19
|
- [feature] Asterisk can be used as token character.
|
data/Documentation.md
ADDED
@@ -0,0 +1,297 @@
|
|
1
|
+
# Documentation
|
2
|
+
|
3
|
+
## The YAML File
|
4
|
+
|
5
|
+
YAML is the preferred because it simplifies the content of the spec file. YAML contains the variables that affect the outcome, and the expected outcome based on rules that involve the said variables.
|
6
|
+
|
7
|
+
```yaml
|
8
|
+
specs:
|
9
|
+
# spec key uniquely identifies a spec. It has to match the ID when the spec
|
10
|
+
# block is invoked in the ruby spec file. Usually the method name.
|
11
|
+
spec_key:
|
12
|
+
description: Spec Description
|
13
|
+
|
14
|
+
variables:
|
15
|
+
param1: [one, two]
|
16
|
+
|
17
|
+
outcomes: # required (dictionary)
|
18
|
+
true: one[0] # sample outcome.
|
19
|
+
|
20
|
+
default: DEFAULT # optional (scalar) fall off value.
|
21
|
+
```
|
22
|
+
|
23
|
+
### Using a subscript when variables clash
|
24
|
+
|
25
|
+
A subscript may be used in cases where a variable token used multiple times.
|
26
|
+
In the example below, the left variable has the subscript of `0`, and the right variable have the subscript of `1`.
|
27
|
+
|
28
|
+
[logic_checker_spec.yml](./spec/examples/rast/logic_checker_spec.yml)
|
29
|
+
|
30
|
+
```yaml
|
31
|
+
specs:
|
32
|
+
Logical AND:
|
33
|
+
variables:
|
34
|
+
left: [false, true]
|
35
|
+
right: [false, true]
|
36
|
+
outcomes: {true: 'true[0] & true[1]'}
|
37
|
+
|
38
|
+
Logical OR:
|
39
|
+
variables:
|
40
|
+
left: [false, true]
|
41
|
+
right: [false, true]
|
42
|
+
outcomes: {true: 'true[0] | true[1]'}
|
43
|
+
|
44
|
+
Logical XOR:
|
45
|
+
variables:
|
46
|
+
left: [false, true]
|
47
|
+
right: [false, true]
|
48
|
+
outcomes: {true: 'false[0] & true[1] | true[0] & false[1]'}
|
49
|
+
```
|
50
|
+
|
51
|
+
### Isolating scenarios
|
52
|
+
|
53
|
+
For troubleshooting purposes, you can use the `include` attribute to focus on one or more scenarios.
|
54
|
+
|
55
|
+
```yaml
|
56
|
+
---
|
57
|
+
specs:
|
58
|
+
'#positive?':
|
59
|
+
variables: {number: [-1, 0, 1]}
|
60
|
+
outcomes: {true: 1}
|
61
|
+
include: 0
|
62
|
+
```
|
63
|
+
|
64
|
+
Running `rspec -fd` will result to
|
65
|
+
|
66
|
+
```
|
67
|
+
Positive: #positive?, ONLY: '0'
|
68
|
+
[false]=[number: 0]
|
69
|
+
|
70
|
+
Finished in 0.00292 seconds (files took 0.26024 seconds to load)
|
71
|
+
1 example, 0 failures
|
72
|
+
```
|
73
|
+
|
74
|
+
|
75
|
+
### Filtering Out Invalid Cases
|
76
|
+
|
77
|
+
In a prior example `HotelFinder`, some cases are invalid. For example, if an
|
78
|
+
aircon is not available, then it makes to sense to check if it is operational
|
79
|
+
not. In such case, we should limit the scenarios with `exclude` clause.
|
80
|
+
|
81
|
+
```yaml
|
82
|
+
# double_example_spec.yml
|
83
|
+
---
|
84
|
+
specs:
|
85
|
+
'#applicable?':
|
86
|
+
variables:
|
87
|
+
Air Conditioning: [false, true]
|
88
|
+
Security: [false, true]
|
89
|
+
Operational: [false, true]
|
90
|
+
Security Grade: [basic, advanced, diplomat]
|
91
|
+
|
92
|
+
# If airconditioning is false, it does not make sense to test if it is
|
93
|
+
# operational. We limit the invalid scenarios to at most 1, so that
|
94
|
+
# a scenario where airconditioning is false will still be tested.
|
95
|
+
exclude: false[0] & false[2] | false[1] & !basic
|
96
|
+
outcomes: {PASSED: 'true[0] & true[1] & true[2] & diplomat'}
|
97
|
+
else: INADEQUATE
|
98
|
+
```
|
99
|
+
|
100
|
+
### Using a default outcome
|
101
|
+
|
102
|
+
Defining the rules to outcomes can be the most time consuming part of the process
|
103
|
+
especially for complex tests. If this example, we can remove the `ERROR` outcome
|
104
|
+
and replace it with `default: ERROR` so that any scenario that don't fall into
|
105
|
+
any of the defined outcomes, will result to the default.
|
106
|
+
|
107
|
+
```yaml
|
108
|
+
---
|
109
|
+
specs:
|
110
|
+
'#prime?':
|
111
|
+
variables:
|
112
|
+
number: [-4, -1, 0, 1, 2, 3, 4, 5, 3331, 5551]
|
113
|
+
|
114
|
+
outcomes:
|
115
|
+
true: 2 | 3 | 5 | 3331
|
116
|
+
false: 1 | 4 | 5551
|
117
|
+
# ERROR: -4 | -1 | 0
|
118
|
+
default: ERROR
|
119
|
+
```
|
120
|
+
|
121
|
+
Here is another simplified example of the above. In case the outcome is of
|
122
|
+
boolean type, we can omit the `default` altogether.
|
123
|
+
```yaml
|
124
|
+
---
|
125
|
+
specs:
|
126
|
+
'#prime?':
|
127
|
+
variables:
|
128
|
+
number: [1, 2, 3, 4, 5, 3331, 5551]
|
129
|
+
|
130
|
+
outcomes:
|
131
|
+
true: 2 | 3 | 5 | 3331
|
132
|
+
```
|
133
|
+
The outcome will now be either `true` or `false`. Do note that the variables
|
134
|
+
list have been simplified and does not check negative numbers for demo
|
135
|
+
purpose only.
|
136
|
+
|
137
|
+
### Optional variables for 1 to 1 outcomes.
|
138
|
+
|
139
|
+
`variables` definition can be omitted when each outcome matches each variables.
|
140
|
+
|
141
|
+
```yaml
|
142
|
+
---
|
143
|
+
specs:
|
144
|
+
'#person_name':
|
145
|
+
outcomes:
|
146
|
+
Will.I.Am: musician
|
147
|
+
Ford: soldier
|
148
|
+
John: personal
|
149
|
+
```
|
150
|
+
|
151
|
+
### Detecting invalid rule where a scenario matches multiple outcomes
|
152
|
+
|
153
|
+
In this example, the scenario `1` is defined to result in both `true`, and
|
154
|
+
`false`, which is impossible.
|
155
|
+
|
156
|
+
```yaml
|
157
|
+
---
|
158
|
+
specs:
|
159
|
+
'#positive?':
|
160
|
+
variables: {number: [-1, 0, 1]}
|
161
|
+
outcomes: {true: 1, false: 1 | -1 | 0}
|
162
|
+
```
|
163
|
+
|
164
|
+
It will result in an error.
|
165
|
+
|
166
|
+
```
|
167
|
+
RuntimeError:
|
168
|
+
#positive? [1] must fall into a unique rule outcome/clause, matched: ["true", "false"]
|
169
|
+
```
|
170
|
+
|
171
|
+
In the same way if a scenario does not fall into any outcome, a similar error
|
172
|
+
will be displayed.
|
173
|
+
|
174
|
+
```
|
175
|
+
RuntimeError:
|
176
|
+
#positive? [1] must fall into a unique rule outcome/clause, matched: []
|
177
|
+
```
|
178
|
+
|
179
|
+
### Using special characters as part of variable tokens.
|
180
|
+
|
181
|
+
An array may be used as variable token, this will allow for the special
|
182
|
+
characters like `!` to be used as part of the token without confusing the rule
|
183
|
+
engine.
|
184
|
+
|
185
|
+
```yaml
|
186
|
+
---
|
187
|
+
specs:
|
188
|
+
'#identify_sentence_type':
|
189
|
+
variables:
|
190
|
+
- "Let's do it!"
|
191
|
+
- "Will this work?"
|
192
|
+
- "Let's make a statement"
|
193
|
+
...
|
194
|
+
|
195
|
+
```
|
196
|
+
|
197
|
+
The rules must then be written in a different way, as arrays.
|
198
|
+
|
199
|
+
```yaml
|
200
|
+
...
|
201
|
+
outcomes:
|
202
|
+
exclamation: ["Let's do it!"]
|
203
|
+
question: ['Will this work?']
|
204
|
+
statement: ["Let's make a statement"]
|
205
|
+
```
|
206
|
+
|
207
|
+
If an operation is involved:
|
208
|
+
|
209
|
+
```yaml
|
210
|
+
outcomes:
|
211
|
+
non-question: ["Let's do it!", '|', "Let's make a statement"]
|
212
|
+
```
|
213
|
+
|
214
|
+
## The spec file
|
215
|
+
|
216
|
+
### Stubbing
|
217
|
+
|
218
|
+
In this example, stubbing is done as you normally would. A `prepare` block is an
|
219
|
+
optional block to organize the parts of the test into preparation and execution
|
220
|
+
parts.
|
221
|
+
|
222
|
+
[worker_spec.rb](./spec/examples/worker_spec.rb)
|
223
|
+
|
224
|
+
```ruby
|
225
|
+
# spec/examples/worker_spec.rb
|
226
|
+
rast Worker do
|
227
|
+
spec '#goto_work?' do
|
228
|
+
prepare do |day_type, dow|
|
229
|
+
allow(subject).to receive(:day_of_week) { dow.to_sym }
|
230
|
+
allow(subject).to receive(:holiday?) { day_type == 'Holiday' }
|
231
|
+
end
|
232
|
+
|
233
|
+
execute { subject.goto_work? ? :Work : :Rest }
|
234
|
+
end
|
235
|
+
end
|
236
|
+
```
|
237
|
+
|
238
|
+
### Using a factory
|
239
|
+
|
240
|
+
See [examples/factory_example.rb](./examples/factory_example.rb)
|
241
|
+
|
242
|
+
```ruby
|
243
|
+
rast FactoryExample do
|
244
|
+
spec '#person_name' do
|
245
|
+
prepare do |service_type|
|
246
|
+
subject.instance_variable_set(:@person, build(service_type.to_sym))
|
247
|
+
end
|
248
|
+
|
249
|
+
execute { subject.person_name }
|
250
|
+
end
|
251
|
+
end
|
252
|
+
```
|
253
|
+
|
254
|
+
### Using doubles
|
255
|
+
|
256
|
+
Suppose we have a HotelFinder class that has a dependency to air conditioning
|
257
|
+
and security
|
258
|
+
|
259
|
+
```ruby
|
260
|
+
rast HotelFinder do
|
261
|
+
spec '#applicable?' do
|
262
|
+
prepare do |with_ac, is_opererational, with_security, security_grade|
|
263
|
+
if with_ac
|
264
|
+
allow(subject)
|
265
|
+
.to receive(:aircon) { double(operational?: is_opererational) }
|
266
|
+
end
|
267
|
+
|
268
|
+
if with_security
|
269
|
+
allow(subject)
|
270
|
+
.to receive(:security) { double(grade: security_grade.to_sym) }
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
execute { subject.applicable? ? :PASSED : :INADEQUATE }
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
```
|
279
|
+
|
280
|
+
### Spec file without yaml
|
281
|
+
|
282
|
+
If a single spec is preferred, like in cases where it's much simplier,
|
283
|
+
the required configuration can be written with similar name except for the
|
284
|
+
`inclusion` and `exclusion`. The difference is due to the name clash with the
|
285
|
+
`include` keyword in ruby.
|
286
|
+
|
287
|
+
```ruby
|
288
|
+
rast Positive do
|
289
|
+
spec '#positive?' do
|
290
|
+
variables({ number: [-1, 0, 1, 2, 3] })
|
291
|
+
outcomes(true: 1)
|
292
|
+
inclusion('!3')
|
293
|
+
exclusion(2)
|
294
|
+
execute { |number| subject.positive?(number) }
|
295
|
+
end
|
296
|
+
end
|
297
|
+
```
|
data/Gemfile
CHANGED
@@ -4,13 +4,11 @@ source 'https://rubygems.org'
|
|
4
4
|
|
5
5
|
git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
|
6
6
|
|
7
|
-
|
8
7
|
group :development, :test do
|
9
8
|
gem 'factory_girl', '~> 4.7'
|
10
9
|
end
|
11
10
|
|
12
11
|
group :test do
|
13
|
-
|
14
12
|
gem 'listen', '>= 3.0.8'
|
15
13
|
gem 'lumberjack', '~> 1.0', '>= 1.0.13'
|
16
14
|
gem 'rb-inotify', '~> 0.9.10'
|
@@ -0,0 +1,122 @@
|
|
1
|
+
# Getting Started (WIP)
|
2
|
+
|
3
|
+
|
4
|
+
## Tutorials
|
5
|
+
|
6
|
+
|
7
|
+
|
8
|
+
### Writing a simple test.
|
9
|
+
|
10
|
+
Suppose we want to create a class that checks if a number is a positive number or not.
|
11
|
+
|
12
|
+
#### Create a spec file `spec/positive_spec.rb`
|
13
|
+
|
14
|
+
```ruby
|
15
|
+
require 'rast'
|
16
|
+
|
17
|
+
rast Positive do
|
18
|
+
spec 'Is Positive Example' do
|
19
|
+
execute { |number| subject.positive?(number) }
|
20
|
+
end
|
21
|
+
end
|
22
|
+
```
|
23
|
+
|
24
|
+
- On line: 1, the library is required:
|
25
|
+
|
26
|
+
```ruby
|
27
|
+
require 'rast'
|
28
|
+
```
|
29
|
+
|
30
|
+
- On line: 3, invoke the DSL:
|
31
|
+
|
32
|
+
```ruby
|
33
|
+
rast Positive do
|
34
|
+
```
|
35
|
+
`Positive` is the fully qualified name of the class or the module to be tested.
|
36
|
+
|
37
|
+
- On line: 4, define the first spec:
|
38
|
+
|
39
|
+
```ruby
|
40
|
+
spec 'Is Positive Example' do
|
41
|
+
```
|
42
|
+
|
43
|
+
`'Is Positive Example'` is a descriptive identifier for the test. It can be the name of the method like `#positive?`.
|
44
|
+
|
45
|
+
- On line: 5, define the `execute` block..
|
46
|
+
|
47
|
+
```ruby
|
48
|
+
execute { |number| subject.positive?(number) }
|
49
|
+
```
|
50
|
+
|
51
|
+
There is a lot going on here.<br>
|
52
|
+
- Inside the block, we define how our subject will be invoked. The `positive?` method is invoked on the `subject`
|
53
|
+
accepting a parameter.
|
54
|
+
- Block parameter `number` will contain the test scenario we want to execute. More on this later. Just know that whichever values are passed here, the `subject` has to be able to handle it correctly.
|
55
|
+
- `subject` is an instance of the module or class that we defined on line: 3.
|
56
|
+
- And lastly, `execute` block expects a return value that will be verified when the spec is run.
|
57
|
+
|
58
|
+
#### Step 2: Defining outcomes and the variables that affects the test.
|
59
|
+
|
60
|
+
For the sake of simplicity, we will define the variables and outcomes in a separate yaml file, mainly because the next
|
61
|
+
steps are purely configurations. Using yaml is completely optional.
|
62
|
+
|
63
|
+
Create a folder `rast` in the same level as the spec file:
|
64
|
+
|
65
|
+
- spec
|
66
|
+
- rast
|
67
|
+
|
68
|
+
Create a yaml file with the same name as the spec, but with `.yml` extension.
|
69
|
+
|
70
|
+
`spec/rast/positive_spec.yml` would contain:
|
71
|
+
|
72
|
+
```yaml
|
73
|
+
specs:
|
74
|
+
Is Positive Exaple:
|
75
|
+
variables: {number: [-1, 0, 1]}
|
76
|
+
outcomes: {true: 1}
|
77
|
+
```
|
78
|
+
|
79
|
+
- On line: 1 is the root configuration element `specs` that will contain one or more specs.
|
80
|
+
- On line: 2 `Is Positive Example` is the spec identifier, this must match what we've defined on `positive_spec.rb:4`
|
81
|
+
- On line: 3, The variables that affect the SUT are defined, in this case there is only one variable called `number`,
|
82
|
+
which has 3 different possibilities `-1`, `0`, and `1`.
|
83
|
+
- On line: 4, This is where outcome to rule mapping is defined.
|
84
|
+
|
85
|
+
### The implementation file
|
86
|
+
|
87
|
+
positive.rb will have:
|
88
|
+
|
89
|
+
```ruby
|
90
|
+
class Positive
|
91
|
+
def positive?(number)
|
92
|
+
number > 0
|
93
|
+
end
|
94
|
+
end
|
95
|
+
```
|
96
|
+
|
97
|
+
## How To's
|
98
|
+
|
99
|
+
### Use token subscript when there's a variable token clash.
|
100
|
+
|
101
|
+
In cases where multiple variables, `left` and `right`, has the same set of tokens `false` and `true`:
|
102
|
+
|
103
|
+
```yaml
|
104
|
+
variables:
|
105
|
+
left: [false, true]
|
106
|
+
right: [false, true]
|
107
|
+
```
|
108
|
+
|
109
|
+
We need a way to uniquely identify the tokens in the `outcomes` configuration. We can do so by using a subscript in the format: `token[n]`
|
110
|
+
For Example:
|
111
|
+
|
112
|
+
```yaml
|
113
|
+
outcomes: {true: 'true[0] & true[1]'}
|
114
|
+
```
|
115
|
+
|
116
|
+
The subscript `0` would refer to the `true` token in the `left` variable and subscript `1` would refer to the `true`
|
117
|
+
token in the `right` variable.
|
118
|
+
|
119
|
+
|
120
|
+
## References
|
121
|
+
|
122
|
+
### Outcomes
|
data/Getting-Started.md
CHANGED
@@ -1,26 +1,12 @@
|
|
1
|
-
# Getting Started
|
1
|
+
# Getting Started (WIP)
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
## Tutorials
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
### Writing a simple test.
|
3
|
+
### A Basic Example
|
10
4
|
|
11
5
|
Suppose we want to create a class that checks if a number is a positive number or not.
|
12
6
|
|
13
|
-
####
|
14
|
-
|
15
|
-
Start by creating a spec file inside your `spec` folder, let's call it `positive_spec.rb`
|
16
|
-
|
17
|
-
- spec
|
18
|
-
- positive_spec.rb
|
7
|
+
#### Create a spec file `spec/positive_spec.rb`
|
19
8
|
|
20
|
-
|
21
|
-
`positive_spec.rb` would look like this:
|
22
|
-
|
23
|
-
```
|
9
|
+
```ruby
|
24
10
|
require 'rast'
|
25
11
|
|
26
12
|
rast Positive do
|
@@ -30,72 +16,19 @@ rast Positive do
|
|
30
16
|
end
|
31
17
|
```
|
32
18
|
|
33
|
-
|
34
|
-
|
35
|
-
```
|
36
|
-
require 'rast'
|
37
|
-
```
|
38
|
-
|
39
|
-
- On line: 3, invoke the DSL:
|
40
|
-
|
41
|
-
```
|
42
|
-
rast Positive do
|
43
|
-
```
|
44
|
-
`Positive` is the fully qualified name of the class or the module to be tested.
|
45
|
-
|
46
|
-
- On line: 4, define the first spec:
|
47
|
-
|
48
|
-
```
|
49
|
-
spec 'Is Positive Example' do
|
50
|
-
```
|
51
|
-
|
52
|
-
`'Is Positive Example'` is a descriptive identifier for the test. It can be the name of the method like `#positive?`.
|
53
|
-
|
54
|
-
- On line: 5, define the `execute` block..
|
55
|
-
|
56
|
-
```
|
57
|
-
execute { |number| subject.positive?(number) }
|
58
|
-
```
|
59
|
-
|
60
|
-
There is a lot going on here.<br>
|
61
|
-
- Inside the block, we define how our subject will be invoked. The `positive?` method is invoked on the `subject`
|
62
|
-
accepting a parameter.
|
63
|
-
- Block parameter `number` will contain the test scenario we want to execute. More on this later. Just know that whichever values are passed here, the `subject` has to be able to handle it correctly.
|
64
|
-
- `subject` is an instance of the module or class that we defined on line: 3.
|
65
|
-
- And lastly, `execute` block expects a return value that will be verified when the spec is run.
|
66
|
-
|
67
|
-
#### Step 2: Defining outcomes and the variables that affects the test.
|
68
|
-
|
69
|
-
For the sake of simplicity, we will define the variables and outcomes in a separate yaml file, mainly because the next
|
70
|
-
steps are purely configurations. Using yaml is completely optional.
|
71
|
-
|
72
|
-
Create a folder `rast` in the same level as the spec file:
|
73
|
-
|
74
|
-
- spec
|
75
|
-
- rast
|
19
|
+
#### Create a spec configuration `spec/rast/positive_spec.yml`
|
76
20
|
|
77
|
-
|
78
|
-
|
79
|
-
`spec/rast/positive_spec.yml` would contain:
|
80
|
-
|
81
|
-
```
|
21
|
+
```yaml
|
82
22
|
specs:
|
83
23
|
Is Positive Exaple:
|
84
24
|
variables: {number: [-1, 0, 1]}
|
85
25
|
outcomes: {true: 1}
|
86
26
|
```
|
87
27
|
|
88
|
-
|
89
|
-
- On line: 2 `Is Positive Example` is the spec identifier, this must match what we've defined on `positive_spec.rb:4`
|
90
|
-
- On line: 3, The variables that affect the SUT are defined, in this case there is only one variable called `number`,
|
91
|
-
which has 3 different possibilities `-1`, `0`, and `1`.
|
92
|
-
- On line: 4, This is where outcome to rule mapping is defined.
|
93
|
-
|
94
|
-
### The implementation file
|
28
|
+
The class to test:
|
95
29
|
|
96
|
-
|
97
|
-
|
98
|
-
```
|
30
|
+
```ruby
|
31
|
+
# positive.rb
|
99
32
|
class Positive
|
100
33
|
def positive?(number)
|
101
34
|
number > 0
|
@@ -103,37 +36,21 @@ class Positive
|
|
103
36
|
end
|
104
37
|
```
|
105
38
|
|
106
|
-
|
39
|
+
Running the test:
|
107
40
|
|
108
|
-
|
41
|
+
`$ rspec -fd spec/examples/positive_spec.rb`
|
109
42
|
|
110
|
-
|
43
|
+
Test result:
|
111
44
|
|
112
45
|
```
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
We need a way to uniquely identify the tokens in the `outcomes` configuration. We can do so by using a subscript in the format: `token[n]`
|
119
|
-
For Example:
|
46
|
+
Positive: #positive?
|
47
|
+
[false]=[number: -1]
|
48
|
+
[false]=[number: 0]
|
49
|
+
[true]=[number: 1]
|
120
50
|
|
51
|
+
Finished in 0.00471 seconds (files took 0.47065 seconds to load)
|
52
|
+
3 examples, 0 failures
|
121
53
|
```
|
122
|
-
outcomes: {true: 'true[0] & true[1]'}
|
123
|
-
```
|
124
|
-
|
125
|
-
The subscript `0` would refer to the `true` token in the `left` variable and subscript `1` would refer to the `true`
|
126
|
-
token in the `right` variable.
|
127
|
-
|
128
|
-
|
129
|
-
## References
|
130
|
-
|
131
|
-
### Outcomes
|
132
|
-
|
133
|
-
|
134
|
-
## Current Limitations.
|
135
|
-
|
136
|
-
|
137
|
-
|
138
54
|
|
55
|
+
## How To's
|
139
56
|
|