Use the BDD(Cucumber) to test the RESTful API.
-
Install in your project:
npm install --save-dev api-bdd-test mocha chai supertest loopback-supertest
-
mkdir
test
in your project root folder -
generate the
mocha.opts
file in the test folder:--timeout 10000 --ui spec --growl --colors node_modules/api-bdd-test/index.js
- Or run
mocha --ui spec node_modules/api-bdd-test/index.js
directly.
-
generate the
.api-bdd-test.json|.cson|.yml
in the root folder or test folder:language: English server: "http://localhost:3000" root: "/api" libs: "./libs" steps: "./steps" features: "./features"
The feature specifications in the features
folder for reading and testing.
The language
is the default bdd language used in the specifications.
The server
is the api server default url.
The libs
, steps
and features
are the folders to store. the defauls is to
in the test
folder.
- test
- ./features
- a.feature
- ./steps
- a.steps.js
- b-step.js
- ./libs
- some.lib.js
- some.dict.js
- ./features
- tag with
@only
before the scenario to execute the scenario only. - tag with
@pending
before the scenario to stop the scenario. - tag with
@before
before the scenario to turn the scenario to a before feature hook. - tag with
@after
before the scenario to turn the scenario to a after feature hook. - tag with
@beforeEach
before the scenario to turn the scenario to a before each scenario hook. - tag with
@afterEach
before the scenario to turn the scenario to a after each scenario hook. - tag with
@beforeStep
before the scenario to turn the before each step hook. - tag with
@afterStep
before the scenario to turn the after each step hook.
@only
Scenario Calc two value
language supports with:
- File name postfix: a.english.feature
- first line of the file:
# language: English
the server
, root/app
, resource
could be setting in .api-bdd-test.json|.cson|.yml
file.
Or as the annotations in a feature file.
the genernal api steps:
/(GET|HEAD|DEL(?:ETE)?)\s+$string/
/(GET|HEAD|DEL(?:ETE)?|POST|PATCH|PUT)\s+$string[:]\n$object/
- the object is cson format
- data: send to
- heads:
- type: accepting the canonicalized MIME type name complete with type/subtype, or simply the extension name such as "xml", "json", "png", etc, defaults to 'json'
- queries:
- fields:
- accepts:
- attachments:
- explain to see http://visionmedia.github.io/superagent/
/(?:last|prev(?:ious)?)\\s+results?\s+(?:should\s+)?(be|is|are|includes?)\n$object/
/(?:last|prev(?:ious)?)\s+status\s*(?:code)?\\s*(?:should\\s+)?((?:be|is)(?:n't|\s+not)?)\s*[:]?\s*$integer/
- keep the
result.body.id
to 'myvar'
eg,
Feature: Standard API Test
@before
Scenario: empty data before feature running
Given DELETE "bottle"
Scenario: POST and Get result
# POST 'http://127.0.0.1:3000/api/bottle'
# with data
#
Given POST "bottle":
----
type: 'json'
data:
id: 10
a: 13
----
Then The last status code should be: 200
And The last status code should be not: 400
And The last result should be:
----
id: 10
a: 13
----
And keep the result of "body.id" to "myid"
And keep the `result.body.id` to "myid1"
And keep the result to "myres"
And expect the stored `myid` equal 10
And expect the stored `myid1` equal 10
And expect the stored `myid` is not equal 0
And expect the kept `myid` least 1
the genernal Chinese api steps:
新建资源:"resource",其内容为\n$object
编辑(ID|编号)是:"the-id"的资源:"resource",其内容为\n$object
删除(ID|编号)是:"the-id"的资源:"resource"
检[查测]是否存在资源\\s*[::]?[(( ]$identifier(?:[)) ]\\s*[,,.。])?\\s*[::]?$string
/上次[的]?(?:状态[码]?|status)[为是::]\s*$identifier/
/上次[的]?(?:结果|body)([为是::]|包[括含][::]?)\s*\n$object/
(?:获[取得]|取[得]?)(?:id|ID|编号)[为是::]?$string的?资源\\s*[::]?[((]?$identifier(?:[))]?\\s*[,,.。])?[的其]?(?:内容|结果)[为是]?\\n$object
(?:获[取得]|取得?)资源\\s*[::]?[((]?$identifier(?:[))]?\\s*[,,.。])?\\s*[::]?$string
([不]?会?存在|没有?|有)(?:id|ID|编号)[为是::]?$string的?资源\\s*[::]?[((]?$identifier(?:[))]?\\s*[,,.。])?
/登[录陆]\s*用户[::]\s*$string\s*[,,]\s*密码[::]\s*$string/
/注销用户|退出系统/
/(?:记[住下忆]?|保[存留])结果的(?:属性)?$string到[::]?$string/
记住结果到"myvar"
保存的"mvar"等于xxx
/(不?存在)(?:记[住下忆]?|保[存留]的)?\s*$string$/
列[出举]资源\\s*[::]?[(( ]$identifier(?:[)) ]\\s*[,,.。])?
[搜查][索询找]资源\\s*'+resNameRegEx+'按?(?:指定|如下)?(?:条件|设置)[::]?$object
记住`result.body[0].id`到"myvar"
获得id为"id",过滤条件为"xxx"的资源: bottle
The all scripts in the libs
folder will be loaded.
The a.steps.js
script in the steps
folder will be loaded for a.feature
.
The steps
script file extend name should be end with [.-]step[s]?\\.(js|coffee)
The libs
script(extend name should be end with[.-](lib[s]?|dict[s]?)\.(js|coffee)
) should be like this:
var Dictionary = Yadda.Dictionary;
var converters = Yadda.converters;
module.exports = function(dictionary){
dictionary
.define('integer', /(\d+)/, converters.integer);
this
.define('Expect $integer to be an integer', function(i, next) {
assert.equal(typeof i, 'number');
assert(i % 1 === 0);
next();
});
}
The steps
script(file name should be #{featureName}(.#{lang})?.step[s]?.(js|coffee)
) should be like this:
//the `this` is the Yadda.Library() (bind to current language)
//the dict is the Yadda.Dictionary()
module.exports = function(dict){
this.given("$integer green bottles are standing on the wall", function(number_of_bottles) {
wall = new Wall(number_of_bottles);
wall.printStatus();
})
.when("$integer green bottle accidentally falls", function(number_of_falling_bottles) {
wall.fall(number_of_falling_bottles);
console.log("%s bottle falls", number_of_falling_bottles);
})
.then("there are $integer green bottles standing on the wall", function(number_of_bottles) {
assert.equal(number_of_bottles, wall.bottles);
wall.printStatus();
});
}
- no back ref in regexp.
- no optional group on
$xxx
defininition. eg,$string?
should be wrong. - report the
<-- Undefined Step
error:- Duplication Regexp Step
- Optional Group in the regexp step.
- [Broken] the
resNameRegEx
(Chinese) force use limiter to get the identifier.
- Add Special Scenarios
- add the before/after annotations for feature hook
- add the beforeEach/afterEach annotations for Scenario hook
- add the beforeStep/afterStep annotations for step hook
- referernce the variaible which stored by steps. use the "``" delimiter instead.
- it's an one line coffee-script code in this delimiter.
\
"#{myid}"``
- it's an one line coffee-script code in this delimiter.