-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathdoc.go
249 lines (145 loc) · 8.01 KB
/
doc.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
/*Package mspec is a BDD context/specification testing package for Go(Lang) with a strong emphases on spec'ing your feature(s) and scenarios first, before any code is written using as little syntax noise as possible. This leaves you free to think of your project and features as a whole without the distraction of writing any code with the added benefit of having tests ready for your project.
[](https://godoc.org/github.com/eduncan911/mspec) holds the source documentation (where else?)
Features
* Uses natural language (Given/When/Then)
* Stubbing
* Human-readable outputs
* HTML output (coming soon)
* Use custom Assertions
* Configuration options
* Uses Testify's rich assertions
* Uses Go's built-in testing.T package
Go Get It
Install it with one line of code:
go get github.com/eduncan911/gomspec
There are no external dependencies and it is built against Go's internal packages. The only dependency is that you have [GOPATH setup normaly](https://golang.org/doc/code.html).
Go Stub Something
Create a new file to hold your specs.
pico sample_test.go
Using Dan North's original BDD definitions, you spec code using the Given/When/Then storyline similar to:
Feature X
Given a context
When an event occurs
Then it should do something
But this is just a static example. Let's take a real example from one of my projects:
Feature Public API Contracts
Given an invalid Api
When GetStatus is called
Then it should return an invalid status code
Then it should return an error message
Then it should return an 200 htp status code.
You represent these thoughts in code like this:
package main
import (
. "github.com/eduncan911/gomspec"
"testing"
)
func Test_Public_API_Contract(t *testing.T) {
Given(t, "an invalid Api", func(when When) {
when("GetStatus is called", func(it It) {
it("should return an invalid status code")
it("should return an error message")
it("should return an 200 http status code")
})
// we can start designing our package immediately by specifying more contexts
// and specs. there is no fuddling with real code that gets us off topic.
when("GetUsers is called")
})
}
Note that `Given`, `when` and `it` all have optional variadic parameters. This allows you to spec things out with as little or as far as you want.
That's it. Now run it:
$ go test
Feature: API Contract
Given an invalid Api
When GetStatus is called
» It should return an invalid status code «-- NOT IMPLEMENTED
» It should return an error message «-- NOT IMPLEMENTED
» It should return an 200 http status code «-- NOT IMPLEMENTED
When GetUsers is called
PASS
ok github.com/eduncan911/gomspec 0.001s
Print it out and stick it on your office door for everyone to see what you are working on.
This is actually colored output in Terminal:
It is not uncommon to go back and tweak your stories over time as you talk with your domain experts, modifying exactly the scenarios and specifications that should happen.
`GoMSpec` is a testing package for the Go framework that extends Go's built-in testing package. It is modeled after the BDD Feature Specification story workflow such as:
With Feature X
Given a context
When an event occurs
Then it should do something
Currently it has an included `Expectation` struct that mimics basic assertion behaviors. Future plans may allow for custom assertion packages (like testify).
Getting it
go get github.com/eduncan911/gomspec
Importing it
import . "github.com/eduncan911/gomspec"
Writing Specs
// dogs_test.go
//
package dogs
import (
. "github.com/eduncan911/gomspec"
"testing"
)
func Test_Washing_Dogs(t *testing.T) {
Given(t, "a dog that has been painted red\nand the paint is washable\nand no one has washed the dog yet", func(when When) {
d := BirthDog()
d.Paint(&paint{
color: "red",
iswashable: true,
})
when("the dog is washed", func(it It) {
d.Wash()
it("should have the paint come off", func(expect Expect) {
expect(d.paint).ToNotExist()
})
it("should be a normal color", func(expect Expect) {
expect(d.color).ToEqual(normalColor)
})
it("should smell like a clean dog", func(expect Expect) {
expect(d.washed).ToEqual(true)
})
})
})
}
Testing it
go test
Which outputs the following:
Feature: Washing Dogs
Given a dog that has been painted red
and the paint is washable
and no one has washed the dog yet
When the dog is washed
» It should have the paint come off
» It should be a normal color
» It should smell like a clean dog
PASS
ok github.com/eduncan911/gomspec/examples 0.007s
Nice eh?
Testing
There is nothing like using a testing package to test itself. There is
some nice rich information available.
go test
## Examples
Be sure to check out more examples in the examples/ folder.
$ cd examples/
/examples$ go test
Or just open the files and take a look. That's the most important part anyways.
Why Another BDD Framework
When evaluating several BDD frameworks, [Pranavraja's Zen](https://github.com/pranavraja/zen) package for Go came close - really close; but, it was lacking the more "story" overview I've been accustomed to over the years with [Machine.Specifications](https://github.com/machine/machine.specifications) in C# (.NET land).
Do note that there is something to be said for simple testing in Go (and simple coding); therefore, if you are the type to keep it short and sweet and just code, then you may want to use Pranavraja's framework as it is just the context (Desc) and specs writing.
I forked his code and submitted a few bug tweaks at first. But along the way, I started to have grand visions of my soul mate [Machine.Specifications](https://github.com/machine/machine.specifications) (which is called MSpec for short) for BDD testing. The ease of defining complete stories right down to the scenarios without having to implement them intrigued me in C#. It freed me from worrying about implementation details and just focus on the feature I was writing: What did it need to do? What context was I given to start with? What should it do?
So while using Pranavraja's Zen framework, I kept asking myself: Could I bring those MSpec practices to Go, using a bare-bones framework? Ok, done. And since it was so heavily inspired by Aaron's MSpec project, I kept the name going here: `GoMSpec`.
While keeping backwards compatibility with his existing Zen framework, I defined several goals for this package:
* Had to stay simple with Give/When/Then definitions. No complex coding.
* Keep the low syntax noise from the existing Zen package.
* I had to be able to write features, scenarios and specs with no implementation details needed.
No Implementation Details needed
That last goal above is key and I think is what speaks truly about what BDD is: focus on the story, feature and/or context you are designing - focus on the Behavior! I tended to design my C# code using Machine.Specifications in this BDD-style by writing entire stories and grand specs up front - designing the system I was building, or the feature I was extending. In C# land, it's not unheard of me hitting 50 to 100 specs across a single feature and a few different contexts in an hour or two, before writing any code. Which at that point, I had everything planned out pretty much the way it should behave.
So with this framework, I came up with a simple method name, `NA()`, to keep the syntax noise down.
Therefore, you are free to code specs with just a little syntax noise:
// defining specs in Go, without imeplementing or stubbing code
it("should do this", NA())
it("should do that", NA())
it("should not be red", NA())
it("should not be from the year 8,000 BC", NA())
*/
package mspec