Improved overall testing coverage

This commit is contained in:
Syrus Akbary 2015-10-10 14:53:46 -07:00
parent 61d5556beb
commit 6eb1a48cb2
14 changed files with 227 additions and 10 deletions

View File

@ -66,6 +66,10 @@ class DjangoModelField(Field):
resolved = super(DjangoModelField, self).resolve(instance, args, info)
schema = info.schema.graphene_schema
_type = self.get_object_type(schema)
assert _type, ("Field %s cannot be retrieved as the "
"ObjectType is not registered by the schema" % (
self.field_name
))
return _type(resolved)
@memoize

View File

@ -121,7 +121,7 @@ class Field(object):
"""
Displays the module, class and name of the field.
"""
path = '%s[%s]' % (self.__class__.__name__, str(self.field_type))
path = '%s.%s' % (self.__class__.__module__, self.__class__.__name__)
name = getattr(self, 'field_name', None)
if name is not None:
return '<%s: %s>' % (path, name)

View File

@ -19,6 +19,9 @@ class ObjectTypeMeta(type):
def is_interface(cls, parents):
return Interface in parents
def is_mutation(cls, parents):
return Mutation in parents
def __new__(cls, name, bases, attrs):
super_new = super(ObjectTypeMeta, cls).__new__
parents = [b for b in bases if isinstance(b, cls)]
@ -44,6 +47,10 @@ class ObjectTypeMeta(type):
new_class.add_to_class('_meta', new_class.options_cls(meta))
new_class._meta.interface = new_class.is_interface(parents)
new_class._meta.mutation = new_class.is_mutation(parents)
assert not (new_class._meta.interface and new_class._meta.mutation)
# Add all attributes to the class.
for obj_name, obj in attrs.items():
new_class.add_to_class(obj_name, obj)
@ -155,5 +162,9 @@ class ObjectType(six.with_metaclass(ObjectTypeMeta, BaseObjectType)):
pass
class Mutation(six.with_metaclass(ObjectTypeMeta, BaseObjectType)):
pass
class Interface(six.with_metaclass(ObjectTypeMeta, BaseObjectType)):
pass

View File

@ -15,9 +15,9 @@ def get_node_type(schema, obj):
return obj.internal_type(schema)
def get_node(schema, globalId, *args):
resolvedGlobalId = from_global_id(globalId)
_type, _id = resolvedGlobalId.type, resolvedGlobalId.id
def get_node(schema, global_id, *args):
resolved_global_id = from_global_id(global_id)
_type, _id = resolved_global_id.type, resolved_global_id.id
object_type = schema.get_type(_type)
if not object_type or not issubclass(object_type, BaseNode):
raise Exception("The type %s is not a Node" % _type)

View File

@ -2,6 +2,7 @@ from django.conf.urls import url
from graphene.contrib.django.views import GraphQLView
import graphene
from graphene import Schema
from graphene.contrib.django.types import (
DjangoNode,
@ -20,9 +21,14 @@ class Character(DjangoNode):
class Human(DjangoNode):
raises = graphene.StringField()
class Meta:
model = Article
def resolve_raises(self, *args):
raise Exception("This field should raise exception")
def get_node(self, id):
pass

View File

@ -72,6 +72,14 @@ def test_client_get_good_query(settings, client):
assert json_response == expected_json
def test_client_get_good_query_with_raise(settings, client):
settings.ROOT_URLCONF = 'tests.contrib_django.test_urls'
response = client.get('/graphql', {'query': '{ raises }'})
json_response = format_response(response)
assert json_response['errors'][0]['message'] == 'This field should raise exception'
assert json_response['data']['raises'] is None
def test_client_post_good_query(settings, client):
settings.ROOT_URLCONF = 'tests.contrib_django.test_urls'
response = client.post('/graphql', json.dumps({'query': '{ headline }'}), 'application/json')

View File

@ -4,6 +4,7 @@ from pytest import raises
from graphene.core.fields import (
Field,
StringField,
NonNullField
)
from graphene.core.options import Options
@ -27,6 +28,9 @@ class ObjectType(object):
def can_resolve(self, *args):
return True
def __str__(self):
return "ObjectType"
ot = ObjectType()
ObjectType._meta.contribute_to_class(ObjectType, '_meta')
@ -69,6 +73,12 @@ def test_stringfield_type():
assert f.internal_type(schema) == GraphQLString
def test_nonnullfield_type():
f = NonNullField(StringField())
f.contribute_to_class(ot, 'field_name')
assert isinstance(f.internal_type(schema), GraphQLNonNull)
def test_stringfield_type_required():
f = StringField(required=True)
f.contribute_to_class(ot, 'field_name')
@ -108,3 +118,61 @@ def test_field_resolve_type_custom():
f.contribute_to_class(ot, 'field_name')
field_type = f.get_object_type(s)
assert field_type == ot
def test_field_orders():
f1 = Field(None)
f2 = Field(None)
assert f1 < f2
def test_field_orders_wrong_type():
field = Field(None)
try:
assert not field < 1
except TypeError:
# Fix exception raising in Python3+
pass
def test_field_eq():
f1 = Field(None)
f2 = Field(None)
assert f1 != f2
def test_field_eq_wrong_type():
field = Field(None)
assert field != 1
def test_field_hash():
f1 = Field(None)
f2 = Field(None)
assert hash(f1) != hash(f2)
def test_field_none_type_raises_error():
s = Schema()
f = Field(None)
f.contribute_to_class(ot, 'field_name')
with raises(Exception) as excinfo:
f.internal_field(s)
assert str(excinfo.value) == "Internal type for field ObjectType.field_name is None"
def test_field_str():
f = StringField()
f.contribute_to_class(ot, 'field_name')
assert str(f) == "ObjectType.field_name"
def test_field_repr():
f = StringField()
assert repr(f) == "<graphene.core.fields.StringField>"
def test_field_repr_contributed():
f = StringField()
f.contribute_to_class(ot, 'field_name')
assert repr(f) == "<graphene.core.fields.StringField: field_name>"

View File

@ -0,0 +1,18 @@
from graphene.core.scalars import (
GraphQLSkipField
)
def test_skipfield_serialize():
f = GraphQLSkipField
assert f.serialize('a') is None
def test_skipfield_parse_value():
f = GraphQLSkipField
assert f.parse_value('a') is None
def test_skipfield_parse_literal():
f = GraphQLSkipField
assert f.parse_literal('a') is None

View File

@ -109,3 +109,33 @@ def test_schema_get_type_map():
schema.schema.get_type_map().keys(),
['__Field', 'String', 'Pet', 'Character', '__InputValue', '__Directive', '__TypeKind', '__Schema', '__Type', 'Human', '__EnumValue', 'Boolean']
)
def test_schema_no_query():
schema = Schema(name='My own schema')
with raises(Exception) as excinfo:
schema.schema
assert 'define a base query type' in str(excinfo)
def test_schema_register():
schema = Schema(name='My own schema')
@schema.register
class MyType(ObjectType):
type = StringField(resolve=lambda *_: 'Dog')
assert schema.get_type('MyType') == MyType
def test_schema_introspect():
schema = Schema(name='My own schema')
class MyType(ObjectType):
type = StringField(resolve=lambda *_: 'Dog')
schema.query = MyType
introspection = schema.introspect()
assert '__schema' in introspection

View File

@ -0,0 +1,43 @@
from pytest import raises
import graphene
from graphene import relay
schema = graphene.Schema()
class MyType(object):
name = 'my'
class MyNode(relay.Node):
name = graphene.StringField()
@classmethod
def get_node(cls, id):
return MyNode(MyType())
class Query(graphene.ObjectType):
my_node = relay.NodeField(MyNode)
schema.query = Query
def test_nodefield_query():
query = '''
query RebelsShipsQuery {
myNode(id:"TXlOb2RlOjE=") {
name
}
}
'''
expected = {
'myNode': {
'name': 'my'
}
}
result = schema.execute(query)
assert not result.errors
assert result.data == expected

View File

@ -1,18 +1,28 @@
from collections import namedtuple
from .models import Ship, Faction
from .models import Ship, Faction, Character
def initialize():
human = Character(
name='Human'
)
human.save()
droid = Character(
name='Droid'
)
droid.save()
rebels = Faction(
id='1',
name='Alliance to Restore the Republic',
hero=human
)
rebels.save()
empire = Faction(
id='2',
name='Galactic Empire',
hero=droid
)
empire.save()

View File

@ -2,8 +2,16 @@ from __future__ import absolute_import
from django.db import models
class Character(models.Model):
name = models.CharField(max_length=50)
def __str__(self):
return self.name
class Faction(models.Model):
name = models.CharField(max_length=50)
hero = models.ForeignKey(Character)
def __str__(self):
return self.name

View File

@ -4,7 +4,8 @@ from graphene.contrib.django import (
DjangoObjectType,
DjangoNode
)
from .models import Ship as ShipModel, Faction as FactionModel
from .models import (
Ship as ShipModel, Faction as FactionModel, Character as CharacterModel)
from .data import (
getFaction,
getShip,
@ -17,7 +18,6 @@ schema = graphene.Schema(name='Starwars Django Relay Schema')
class Ship(DjangoNode):
class Meta:
model = ShipModel
@ -26,8 +26,13 @@ class Ship(DjangoNode):
return Ship(getShip(id))
class Faction(DjangoNode):
@schema.register
class CharacterModel(DjangoObjectType):
class Meta:
model = CharacterModel
class Faction(DjangoNode):
class Meta:
model = FactionModel

View File

@ -14,6 +14,9 @@ def test_correct_fetch_first_ship_rebels():
query RebelsShipsQuery {
rebels {
name,
hero {
name
}
ships(first: 1) {
edges {
node {
@ -27,6 +30,9 @@ def test_correct_fetch_first_ship_rebels():
expected = {
'rebels': {
'name': 'Alliance to Restore the Republic',
'hero': {
'name': 'Human'
},
'ships': {
'edges': [
{