corebuilder — Setup devilry core data structures for tests¶
Deprecated since version 3.0: See How to unit-test Devilry.
devilry.project.develop.testhelpers.corebuilder
is a module that makes it easy to create devilry.apps.core.models
data for
tests.
When to use¶
Use this for end-to-end tests and tests where you really need real data. Always try to mock objects instead of creating real data unless you are actually testing something that needs real data.
Howto¶
Each class in the core has a wrapper class in
devilry.project.develop.testhelpers.corebuilder
that makes it easy to perform
operations that we need to setup tests. We call these wrappers builders, and
they are all prefixed with the name of their corresponding core model and
suffixed with Builder
.
Using the builders is very easy:
from devilry.project.develop.testhelpers.corebuilder import NodeBuilder
duck1010builder = NodeBuilder('duckuniversity').add_subject('duck1010')
assert(duck1010builder.subject == Subject.objects.get(short_name='duck1010'))
They can all easily be updated with new attributes:
duck1010builder.update(long_name='DUCK1010 - Programming')
assert(duck1010builder.subject.long_name == 'DUCK1010 - Programming')
And they have sane defaults optimized for testing, so you can easily create a
deeply nested core object. This creates the duck1010-subject with an active
period that started 3 months ago and ends in 3 months, with a single assignment
(week1), with a single group, with deadline one week from now with a single
helloworld.txt
delivery:
from devilry.project.develop.testhelpers.corebuilder import NodeBuilder
from devilry.project.develop.testhelpers.corebuilder import UserBuilder
peterpan = UserBuilder(username='peterpan')
helloworld_filemetabuilder = NodeBuilder('ducku')\
.add_subject('duck1010')\
.add_6month_active_period('current')\
.add_assignment('week1')\
.add_group(students=[peterpan.user])\
.add_deadline_in_x_weeks(weeks=1)\
.add_delivery()\
.add_filemeta(filename='helloworld.txt', data='Hello world')
Since we often need to add a single subject or a single active period, we have shortcuts for that:
from devilry.project.develop.testhelpers.corebuilder import SubjectBuilder
from devilry.project.develop.testhelpers.corebuilder import PeriodBuilder
duck1010_builder = SubjectBuilder.quickadd_ducku_duck1010()
currentperiod_builder = PeriodBuilder.quickadd_ducku_duck1010_active()
Note
These shortcuts is not there just to save a couple of keystrokes. They are there to make sure we use a uniform test setup in 98% of our tests. As long as you just need a single subject or period, you MUST use these shortcuts (to get a patch accepted in Devilry).
Magic and defaults¶
The builders have very little magic, but they have some defaults that make sense when testing:
long_name
is set toshort_name
when it is not specified explicitly.All BaseNodes (the models with short and long name) takes the
short_name
as the first argument and thelong_name
as the second argument.Time of delivery (for
DeliveryBuilder
andDealdineBuilder.add_delivery()
) default to now.Default
publishing_time
for assignments is now.UserBuilder defaults to setting email to
<username>@example.com
.
These defaults are all handled in the constructor of their builder-class. All the defaults can be overridden by specifying a value for them.
Reload from DB¶
You often need to create an object that is changed by
the code you are testing, and then check that
the change has made it to the database. All our builders implement
ReloadableDbBuilderInterface
which includes
reload_from_db()
.
ReloadableDbBuilderInterface¶
- class devilry.project.develop.testhelpers.corebuilder.ReloadableDbBuilderInterface¶
All the builders implement this interface.
- update(**attributes)¶
Update the object wrapped by the builder with the given attributes. Saves the object, and reloads it from the database.
- reload_from_db(**attributes)¶
Reloads the object wrapped by the builder from the database. Perfect when you create an object that is changed by the code you are testing, and you want to check that the change has made it to the database.
UserBuilder¶
- class devilry.project.develop.testhelpers.corebuilder.UserBuilder¶
Creates a User object for testing. Also creates the DevilryUserProfile, and methods for editing both the User and the profile.
- __init__(username, full_name=None, email=None)¶
Creates a new User with password set to test, and the
devilry.apps.core.models.DevilryUserProfile
created.- Parameters:
username – The username of the new user.
full_name – Optional full_name. Defaults to
None
.email – Optional email. Defaults to
<username>@example.com
.
- update(**attributes)¶
Update the User with the given attributes. Reloads the object from the database.
- update_profile(**attributes)¶
Update the
devilry.apps.core.models.DevilryUserProfile
with the given attributes. Reloads the object from the database.
NodeBuilder¶
- class devilry.project.develop.testhelpers.corebuilder.NodeBuilder¶
- node¶
The
Node
wrapped by this builder.
- __init__(short_name, long_name=None, **kwargs)¶
Creates a new
Node
with the given attributes.- Parameters:
short_name – The
short_name
of the Node.long_name – The
long_name
of the Node. Defaults toshort_name
ifNone
.kwargs – Other arguments for the Node constructor.
- add_node(*args, **kwargs)¶
Adds a childnode to the node.
args
andkwargs
are forwarded toNodeBuilder
withkwargs['parentnode']
set to thisnode
.- Return type:
- add_subject(*args, **kwargs)¶
Adds a subject to the node.
args
andkwargs
are forwarded toSubjectBuilder
withkwargs['parentnode']
set to thisnode
.- Return type:
SubjectBuilder¶
- class devilry.project.develop.testhelpers.corebuilder.SubjectBuilder¶
-
- __init__(short_name, long_name=None, **kwargs)¶
Creates a new
Subject
with the given attributes.- Parameters:
short_name – The
short_name
of the Subject.long_name – The
long_name
of the Subject. Defaults toshort_name
ifNone
.kwargs – Other arguments for the Subject constructor.
- classmethod quickadd_ducku_duck1010()¶
When we need just a single subject, we use this shortcut method instead of writing:
NodeBuilder('ducku').add_subject('duck1010')
This is not just to save a couple of letters, but also to promote a common setup for simple tests.
- add_period(*args, **kwargs)¶
Adds a period to the subject.
args
andkwargs
are forwarded toPeriodBuilder
withkwargs['parentnode']
set to thissubject
.- Return type:
- add_6month_active_period(*args, **kwargs)¶
Shortcut for adding
add_period()
withstart_time
3*30
days ago, andend_time
in3*30
days.args
andkwargs
is forwarded toadd_period
, but withstart_time
andend_time
set inkwargs
.If no
short_name
is provided, it defaults toactive
.- Return type:
- add_6month_lastyear_period(*args, **kwargs)¶
Shortcut for adding
add_period()
withstart_time
365-30*3
days ago, andend_time
365+3*30
days ago.args
andkwargs
is forwarded toadd_period
, but withstart_time
andend_time
set inkwargs
.If no
short_name
is provided, it defaults tolastyear
. :rtype:PeriodBuilder
.
- add_6month_nextyear_period(*args, **kwargs)¶
Shortcut for adding
add_period()
withstart_time
in365-30*3
days, andend_time
in365+3*30
days.args
andkwargs
is forwarded toadd_period
, but withstart_time
andend_time
set inkwargs
.If no
short_name
is provided, it defaults tonextyear
.- Return type:
PeriodBuilder¶
- class devilry.project.develop.testhelpers.corebuilder.PeriodBuilder¶
-
- __init__(short_name, long_name=None, **kwargs)¶
Creates a new
Period
with the given attributes.- Parameters:
short_name – The
short_name
of the Period.long_name – The
long_name
of the Period. Defaults toshort_name
ifNone
.kwargs – Other arguments for the Period constructor.
- add_assignment(*args, **kwargs)¶
Adds an assignment to the period.
args
andkwargs
are forwarded toAssignmentBuilder
withkwargs['parentnode']
set to thisperiod
.- Return type:
- classmethod quickadd_ducku_duck1010_active()¶
When we need just a single active period, we use this shortcut method instead of writing:
NodeBuilder('ducku').add_subject('duck1010').add_6month_active_period('current')
This is not just to save a couple of letters, but also to promote a common setup for simple tests.
AssignmentBuilder¶
- class devilry.project.develop.testhelpers.corebuilder.AssignmentBuilder¶
- assignment¶
The
Assignment
wrapped by this builder.
- __init__(short_name, long_name=None, **kwargs)¶
Creates a new
Assignment
with the given attributes.- Parameters:
short_name – The
short_name
of the Assignment.long_name – The
long_name
of the Assignment. Defaults toshort_name
ifNone
.publishing_time – The
publishing_time
of the Assignment. Defaults to now.kwargs – Other arguments for the Assignment constructor.
- add_group(*args, **kwargs)¶
Adds an assignment group to the period.
args
andkwargs
are forwarded toAssignmentGroupBuilder
withkwargs['parentnode']
set to thisassignment
.- Return type:
AssignmentGroupBuilder¶
- class devilry.project.develop.testhelpers.corebuilder.AssignmentGroupBuilder¶
- assignment_group¶
The
AssignmentGroup
wrapped by this builder.
- __init__(students=[], candidates=[], examiners=[], **kwargs)¶
Creates a new
AssignmentGroup
with the given attributes.- Parameters:
students – Forwarded to
add_students()
.candidates – Forwarded to
add_candidates()
.examiners – Forwarded to
add_examiners()
.kwargs – Arguments for the AssignmentGroup constructor.
- add_students(*users)¶
Add the given users as candidates without a candidate ID on this assignment group.
- Returns:
self
(to enable us to nest the method call).
- add_examiners(*users)¶
Add the given users as examiners on this assignment group.
- Returns:
self
(to enable us to nest the method call).
- add_students(*candidates)¶
Add the given candidates to this assignment group.
- Parameters:
candidates –
devilry.apps.core.models.Candidate
objects.- Returns:
self
(to enable us to nest the method call).
- add_deadline(*args, **kwargs)¶
Adds an deadline to the assignment.
args
andkwargs
are forwarded toDeadlineBuilder
withkwargs['assignment_group']
set to thisassignment_group
.- Return type:
- add_deadline_in_x_weeks(weeks, *args, **kwargs)¶
Calls
add_deadline()
withkwargs[deadline]
setweeks
weeks in the future.- Return type:
- add_deadline_x_weeks_ago(weeks, *args, **kwargs)¶
Calls
add_deadline()
withkwargs[deadline]
setweeks
weeks in the past.- Return type:
DeadlineBuilder¶
- class devilry.project.develop.testhelpers.corebuilder.DeadlineBuilder¶
- deadline¶
The
Deadline
wrapped by this builder.
- __init__(**kwargs)¶
Creates a new
AssignmentGroup
with the given attributes.- Parameters:
kwargs – Arguments for the Deadline constructor.
- add_delivery(**kwargs)¶
Adds a delivery to the deadline.
args
andkwargs
are forwarded toDeliveryBuilder
withkwargs['deadline']
set to thisdeadline
andkwargs['successful']
defaulting toTrue
.- Parameters:
kwargs – Extra kwargs for the
DeliveryBuilder
constructor.- Return type:
- add_delivery_after_deadline(timedeltaobject, **kwargs)¶
Add a delivery
timedeltaobject
time after this deadline expires.Shortcut that calls
add_delivery()
withkwargs['time_of_delivery']
set todeadline.deadline + timedeltaobject
.Example - add delivery 3 weeks and 2 hours after deadline:
from datetime import datetime, timedelta deadlinebuilder = DeadlineBuilder(deadline=datetime(2010, 1, 1)) deadlinebuilder.add_delivery_after_deadline(timedelta(weeks=3, hours=2))
- Parameters:
kwargs – Extra kwargs for the
DeliveryBuilder
constructor.- Return type:
- add_delivery_before_deadline(timedeltaobject, **kwargs)¶
Add a delivery
timedeltaobject
time before this deadline expires.Shortcut that calls
add_delivery()
withkwargs['time_of_delivery']
set todeadline.deadline + timedeltaobject
.Example - add delivery 5 hours before deadline:
from datetime import datetime, timedelta deadlinebuilder = DeadlineBuilder(deadline=datetime(2010, 1, 1)) deadlinebuilder.add_delivery_before_deadline(timedelta(hours=5))
- Parameters:
kwargs – Extra kwargs for the
DeliveryBuilder
constructor.- Return type:
- add_delivery_x_hours_after_deadline(timedeltaobject, **kwargs)¶
Add a delivery
hours
hours after this deadline expires.Shortcut that calls
add_delivery_after_deadline()
with timedeltaobject set totimedelta(hours=hours)
.- Parameters:
hours – Number of hours.
kwargs – Extra kwargs for the
DeliveryBuilder
constructor.
- Return type:
- add_delivery_x_hours_before_deadline(timedeltaobject, **kwargs)¶
Add a delivery
hours
hours before this deadline expires.Shortcut that calls
add_delivery_before_deadline()
with timedeltaobject set totimedelta(hours=hours)
.- Parameters:
hours – Number of hours.
kwargs – Extra kwargs for the
DeliveryBuilder
constructor.
- Return type:
DeliveryBuilder¶
- class devilry.project.develop.testhelpers.corebuilder.DeliveryBuilder¶
- delivery¶
The
Delivery
wrapped by this builder.
- __init__(**kwargs)¶
Creates a new
Delivery
with the given attributes. Iftime_of_delivery
is not provided, it defaults to now.- Parameters:
kwargs – Arguments for the Delivery constructor.
- add_filemeta(**kwargs)¶
Adds a filemeta to the delivery.
kwargs
is forwarded toFilteMetaBuilder
withkwargs['delivery']
set to thisdelivery
.Example:
deliverybuilder.add_filemeta( filename='test.txt', data='This is a test.' )
- Parameters:
kwargs – Kwargs for the
FileMetaBuilder
constructor.- Return type:
- add_feedback(**kwargs)¶
Adds a feedback to the delivery.
kwargs
is forwarded toStaticFeedbackBuilder
withkwargs['delivery']
set to thisdelivery
.Example:
deliverybuilder.add_feedback( points=10, grade='10/100', is_passing_grade=False, saved_by=UserBuilder('testuser').user )
- Parameters:
kwargs – Kwargs for the
StaticFeedbackBuilder
constructor.- Return type:
- add_passed_feedback(**kwargs)¶
Shortcut that adds a passed feedback to the delivery.
kwargs
is forwarded toadd_feedback()
with:points=1
grade="Passed"
is_passing_grade=True
Example:
deliverybuilder.add_passed_feedback(saved_by=UserBuilder('testuser').user)
- Parameters:
kwargs – Extra kwargs for
add_feedback()
. Is updated with :points, grade and is_passing_grade as documented above.- Return type:
- add_failed_feedback(**kwargs)¶
Shortcut that adds a failed feedback to the delivery.
kwargs
is forwarded toadd_feedback()
with:points=0
grade="Failed"
is_passing_grade=False
Example:
deliverybuilder.add_failed_feedback(saved_by=UserBuilder('testuser').user)
- Parameters:
kwargs – Extra kwargs for
add_feedback()
. Is updated with :points, grade and is_passing_grade as documented above.- Return type:
FileMetaBuilder¶
- class devilry.project.develop.testhelpers.corebuilder.FileMetaBuilder¶
- filemeta¶
The
FileMeta
wrapped by this builder.
- __init__(delivery, filename, data)¶
Creates a new
FileMeta
. Since FileMeta just points to files on disk, and creating those files requires iterators and extra stuff that is almost never needed for tests, we provide an easier method for creating files with FileMetaBuilder.- Parameters:
delivery – The Delivery object.
filename – A filename.
data – The file contents as a string.