Skip to content

Commit

Permalink
complete first e2e test
Browse files Browse the repository at this point in the history
  • Loading branch information
yarray committed May 11, 2015
1 parent 23c331d commit 9122fe7
Show file tree
Hide file tree
Showing 9 changed files with 154 additions and 30 deletions.
2 changes: 1 addition & 1 deletion circle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ test:
- docker run --name=api --net='host' -p 80:80 -d avipost
override:
- coverage run --source='.' avipost/manage.py test --settings=avipost.settings.ci
- behave -D manager=avipost/manage.py -D base_url=http://127.0.0.1 e2e/features/
post:
- curl http://127.0.0.1/postcards/
- coverage html -d $CIRCLE_ARTIFACTS
- coveralls
22 changes: 22 additions & 0 deletions e2e/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Use it like:

``` bash
behave -D base_url=http:127.0.0.1:3000 -D manager=avipost/manage.py e2e/features/
```

# Dependencies

The e2e tests use **behave** to do cucumber-like BDD test, and depend on these libraries:

## Library dependencies

* sure: for expressive assertion and error report
* requests: for http requests (for human)
* inflection: for parse plurals
* json-schema-generator: for generate json schema based on example data
* jsonschema: use this though json_schema_generator provides validator, since it has detailed error report

## Command line dependencies

* django: for manage database
* autofixture: with django, for load fixtures
15 changes: 15 additions & 0 deletions e2e/features/environment.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
"""
Hooks for running tests
"""
from steps._fixture import Fixture

def clean_db(context):
Fixture(
context.config.userdata.get('manager')
).clean_db()

def before_scenario(context, _):
clean_db(context)

def after_scenario(context, _):
clean_db(context)
29 changes: 13 additions & 16 deletions e2e/features/postcards.feature
Original file line number Diff line number Diff line change
@@ -1,18 +1,15 @@
Feature: /postcards

Scenario: GET
Given sunsen has 3 Postcards
When GET "/postcards?user=sunsen"
Then request will success(200)
And return 3 items
And each item is as
"""
{
"type" : "object",
"properties" : {
"message" : {"type" : "string"},
"cover": {"type": "string"},
"sender" : {"type" : "string"},
}
}
"""
Scenario: GET
Given server has 5 postcards
When GET "/postcards"
Then request will success(200)
And return 5 items
And is like
"""
[{
"message" : "Hello",
"cover": "http://world.com/0.png",
"sender" : "me"
}]
"""
Empty file added e2e/features/steps/__init__.py
Empty file.
49 changes: 49 additions & 0 deletions e2e/features/steps/_fixture.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
"""
Use django and autofixture to manage test database environment
"""
import subprocess
import os

# implicit dependencies
# import django
# import autofixture


class Fixture(object):

""" utilities to clean up database and load fixture """

def __init__(self, manager):
""" manager: path of manage.py """
self.manager = manager

def exec_manage(self, subcommand, *args):
""" execute command using manage.py """
cmd = (
['python', self.manager, subcommand] +
['--settings=avipost.settings.ci'] +
list(args)
)

devnull = open(os.devnull, 'w')
subprocess.call(cmd, stdout=devnull)

def clean_db(self):
""" clean database """
self.exec_manage('flush', '--noinput')

def load_data(self, model, count):
""" load <count> models
:model: name of model, e.g. Postcard
:count: integer, e.g. 3
"""
self.exec_manage(
'loadtestdata', 'postcards.{0}:{1}'.format(model, count)
)


# for manual test
# if __name__ == '__main__':
# clean_db()
48 changes: 48 additions & 0 deletions e2e/features/steps/crud.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
from urlparse import urljoin

from behave import given, when, then
# implicitly used
import sure
from inflection import singularize
import requests
from json_schema_generator import SchemaGenerator
# We use this instead of validator from json_schema_generator
# because its error reports are far better
from jsonschema import validate

from _fixture import Fixture


# supress requests logging
import logging
logging.getLogger("requests").setLevel(logging.WARNING)


@given('server has {count:d} {item}')
def step_impl(context, count, item):
Fixture(
context.config.userdata.get('manager')
).load_data(singularize(item), count)


@when('GET "{url:S}"')
def step_impl(context, url):
base_url = context.config.userdata.get('base_url')
context.response = requests.get(urljoin(base_url, url))
print(context.response.text)


@then('request will {:w}({code:d})')
def step_impl(context, _, code):
context.response.status_code.should.equal(code)


@then('return {count:d} items')
def step_impl(context, count):
assert len(context.response.json()).should.equal(count)


@then('is like')
def step_impl(context):
schema = SchemaGenerator.from_json(context.text)
validate(context.response.json(), schema.to_dict())
13 changes: 0 additions & 13 deletions e2e/steps/crud.py

This file was deleted.

6 changes: 6 additions & 0 deletions requirements/ci.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,9 @@ psycopg2==2.6
requests==2.6.0
wsgiref==0.1.2
Unipath==1.1
sure==1.2.12
requests==2.6.0
inflection==0.3.1
json-schema-generator==0.3
jsonschema==0.8.0
django-autofixture==0.10.0

0 comments on commit 9122fe7

Please sign in to comment.